This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Using bfd to change the .text section of an executable


Hi,

I am trying to use bfd to change the .text section of existing elf
executable files.  I have successfully used bfd to change selected bytes
in the .text section of a simple elf executable resulting in a new
functioning variant executable.

However, any changes which change the size of the .text section (in this
case appending four noops to the end) the resulting file is no longer a
working executable but rather throws segfaults on execution.

After some investigation it appears that while bfd is updating the lma
address of all sections following the .text section in memory (as shown
in the bfd warnings printed in [1] when running my `copy' program, the
source code for which is included below in [2]) bfd is not making
similar adjustments to the vma field of these sections.

Is it possible to convince bfd to manage vma addresses for me?  I've
tried setting the `user_set_vma' flag to 0 before making the copy, but
to no avail.  Also, attempts to set the vma field of these sections
manually before calling bfd_close don't have any effect on the resulting
output file.

Many Thanks -- Eric

p.s. Please let me know if there is a better forum in which to place
     this question, or if I've left out any information required to
     answer this question.  Thanks

Footnotes: 
[1]  The `copy' program uses bfd to copy the hello executable (compiled
     form a simple hello world C program) into the goodbye executable
     (identical to hello but with four noops appended to .text)
     
     $ ./copy hello goodbye
     BFD: goodbye: section .fini lma 0x804846c adjusted to 0x8048470
     BFD: goodbye: section .rodata lma 0x8048488 adjusted to 0x804848c
     BFD: goodbye: section .eh_frame lma 0x804849c adjusted to 0x80484a0
     .fini has lma 0x8048470 user_set_vma is 1
     .rodata has lma 0x804848c user_set_vma is 1
     .eh_frame has lma 0x80484a0 user_set_vma is 1

     $ objdump -h goodbye |egrep -i "fini|rodata|eh_frame|LMA"
     Idx Name          Size      VMA       LMA       File off  Algn
      13 .fini         0000001c  0804846c  08048470  00000470  2**2
      14 .rodata       00000014  08048488  0804848c  0000048c  2**2
      15 .eh_frame     00000004  0804849c  080484a0  000004a0  2**2

[2] this copy.c program consists of a short main, and a good deal of
     code taken from objcopy.c --- after trying unsuccessfully to expose
     some objcopy functions through a shared library I just copied the
     required code directly into my program.
     
#include "stdio.h"
#include "bfd.h"
#include "elf-bfd.h"

/* What kind of change to perform.  */
enum change_action
{
  CHANGE_IGNORE,
  CHANGE_MODIFY,
  CHANGE_SET
};

/* List of sections to add.  */
struct section_add
{
  /* Next section to add.  */
  struct section_add *next;
  /* Name of section to add.  */
  const char *name;
  /* Name of file holding section contents.  */
  const char *filename;
  /* Size of file.  */
  size_t size;
  /* Contents of file.  */
  bfd_byte *contents;
  /* BFD section, after it has been added.  */
  asection *section;
};

/* Structure used to hold lists of sections and actions to take.  */
struct section_list
{
  struct section_list * next;	   /* Next section to change.  */
  const char *		name;	   /* Section name.  */
  bfd_boolean		used;	   /* Whether this entry was used.  */
  bfd_boolean		remove;	   /* Whether to remove this section.  */
  bfd_boolean		copy;	   /* Whether to copy this section.  */
  enum change_action	change_vma;/* Whether to change or set VMA.  */
  bfd_vma		vma_val;   /* Amount to change by or set to.  */
  enum change_action	change_lma;/* Whether to change or set LMA.  */
  bfd_vma		lma_val;   /* Amount to change by or set to.  */
  bfd_boolean		set_flags; /* Whether to set the section flags.	 */
  flagword		flags;	   /* What to set the section flags to.	 */
};

typedef struct section_rename
{
  const char *            old_name;
  const char *            new_name;
  flagword                flags;
  struct section_rename * next;
}
section_rename;

/* List of sections to be renamed.  */
static section_rename *section_rename_list;

/* Forward Function Declarations */
extern bfd_boolean
copy_object(bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch);
static void setup_section (bfd *, asection *, void *);
static void setup_bfd_headers (bfd *, bfd *);
static void copy_section (bfd *, asection *, void *);
static void get_sections (bfd *, asection *, void *);
static int compare_section_lma (const void *, const void *);
static const char *
find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
		     flagword * returned_flags);
static asymbol * group_signature (asection *group);

/* Symbols and Sections */
static asymbol **isympp = NULL;	/* Input symbols.  */
static asymbol **osympp = NULL;	/* Output symbols that survive stripping.  */
static struct section_add *add_sections; /* sections to add to the output BFD. */
static bfd_vma change_section_address = 0; /* Changes to section addresses.  */
static struct section_list *change_sections;

/* Filling gaps between sections.  */
static bfd_boolean gap_fill_set = FALSE;
static bfd_byte gap_fill = 0;

/* Pad to a given address.  */
static bfd_boolean pad_to_set = FALSE;
static bfd_vma pad_to;

/* Part of an external header file elf/common.h */
#define SHT_NOBITS 8

/* Check if a bfd is writable */
#define	bfd_write_p(abfd) \
  ((abfd)->direction == write_direction || (abfd)->direction == both_direction)

/* Exit status.  */
static int status = 0;

/* Whether to convert debugging information.  */
static bfd_boolean convert_debugging = FALSE;

/* Prefix symbols/sections.  */
static char *prefix_symbols_string = 0;
static char *prefix_sections_string = 0;
static char *prefix_alloc_sections_string = 0;

int main(int argc, char **argv) {
  bfd *ibfd, *obfd;
  asection *asec;
  const bfd_arch_info_type *iarch;

  // tell bfd to get ready
  bfd_init();

  // open the input file
  my_debug("open input file");
  if((ibfd = bfd_openr(argv[1], NULL)) == NULL) {
    bfd_perror("Error opening input file");
    return 1;
  }

  // check the file format <- required for sections to be recognized
  my_debug("check input file format");
  if (!bfd_check_format(ibfd, bfd_object))
    bfd_perror("File Format Error");

  // get the arch_info_type of this bfd
  my_debug("check input arch info");
  if ((iarch = bfd_get_arch_info(ibfd)) == NULL)
    bfd_perror("Error getting the architectural info");

  // open the output file and set the format
  my_debug("open output file");
  if((obfd = bfd_openw(argv[2], NULL)) == NULL) {
    bfd_perror("Error opening output file");
    return 1;
  }
  bfd_set_format(obfd, bfd_object);

  // read the .text section
  if((asec = bfd_get_section_by_name(ibfd, ".text")) == NULL) {
    bfd_perror("bfd_get_section_by_name failed");
    return 1;
  }

  // make a copy of the data from this section, and pad the end with noops
  bfd_byte buf[asec->size+4];
  bfd_get_section_contents(ibfd, asec, buf, 0, asec->size);
  int i;
  for(i=0;i<4;i++) buf[asec->size+i] = 0x90;

  // update the size of this section in the obfd
  if(!bfd_set_section_size(obfd, asec, asec->size+4))
    bfd_perror("ibfd: failed to update .text section size");

  // copy data from ibfd into obfd
  my_debug("copy data");
  if(!(copy_object(ibfd, obfd, iarch))){
    bfd_perror("Error copying over bfd");
    return 1;
  }

  // associate asec with the .text section in obfd
  if((asec = bfd_get_section_by_name(obfd, ".text")) == NULL) {
    bfd_perror("bfd_get_section_by_name failed");
    return 1;
  }
  
  if(!bfd_set_section_contents(obfd, asec, buf, 0, asec->size))
    bfd_perror("obfd: failed to update .text section contents");

  // print a couple of section lma's -- and try to update their vma's
  //   unfortunately these new vma's do not affect the output file
  asec = bfd_get_section_by_name(obfd, ".fini");
  bfd_set_section_vma(obfd, asec, asec->lma);
  printf("%s has lma %#lx user_set_vma is %d\n",
         asec->name, asec->lma, asec->user_set_vma);
  asec = bfd_get_section_by_name(obfd, ".rodata");
  bfd_set_section_vma(obfd, asec, asec->lma);
  printf("%s has lma %#lx user_set_vma is %d\n",
         asec->name, asec->lma, asec->user_set_vma);
  asec = bfd_get_section_by_name(obfd, ".eh_frame");
  bfd_set_section_vma(obfd, asec, asec->lma);
  printf("%s has lma %#lx user_set_vma is %d\n",
         asec->name, asec->lma, asec->user_set_vma);
  
  // close up shop
  if(!bfd_close(ibfd)) bfd_perror("Error closing ibfd");
  if(!bfd_close(obfd)) bfd_perror("Error closing obfd");
  return 0;
}

void my_debug(char *msg){
  if(FALSE) printf("debug: %s\n", msg);
}

/* Find and optionally add an entry in the change_sections list.  */
static struct section_list *
find_section_list (const char *name, bfd_boolean add)
{
  struct section_list *p;

  for (p = change_sections; p != NULL; p = p->next)
    if (strcmp (p->name, name) == 0)
      return p;

  if (! add)
    return NULL;

  p = (struct section_list *) xmalloc (sizeof (struct section_list));
  p->name = name;
  p->used = FALSE;
  p->remove = FALSE;
  p->copy = FALSE;
  p->change_vma = CHANGE_IGNORE;
  p->change_lma = CHANGE_IGNORE;
  p->vma_val = 0;
  p->lma_val = 0;
  p->set_flags = FALSE;
  p->flags = 0;

  p->next = change_sections;
  change_sections = p;

  return p;
}

extern bfd_boolean
copy_object(bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch) {
  bfd_vma start;
  long symcount;
  asection **osections = NULL;
  asection *gnu_debuglink_section = NULL;
  bfd_size_type *gaps = NULL;
  bfd_size_type max_gap = 0;
  long symsize;
  void *dhandle;
  enum bfd_architecture iarch;
  unsigned int imach;

  if (ibfd->xvec->byteorder != obfd->xvec->byteorder
      && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
      && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) {
    printf("Unable to change endianness of input file(s)\n");
    return FALSE;
  }

  if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
    {
      printf("nonfatal error at line:%d\n", 150);
      return FALSE;
    }

  start = bfd_get_start_address (ibfd);

  /* Neither the start address nor the flags
     need to be set for a core file.  */
  if (bfd_get_format (obfd) != bfd_core)
    {
      flagword flags;

      flags = bfd_get_file_flags (ibfd);
      flags &= bfd_applicable_file_flags (obfd);

      if (!bfd_set_start_address (obfd, start)
	  || !bfd_set_file_flags (obfd, flags))
	{
	  printf("nonfatal error at line:%d\n", 168);
	  return FALSE;
	}
    }

  /* Copy architecture of input file to output file.  */
  iarch = bfd_get_arch (ibfd);
  imach = bfd_get_mach (ibfd);
  if (input_arch)
    {
      if (bfd_get_arch_info (ibfd) == NULL
	  || bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown)
	{
	  iarch = input_arch->arch;
	  imach = input_arch->mach;
	}
      // else
      //   printf("Input file ignores binary architecture parameter.\n");
    }
  if (!bfd_set_arch_mach (obfd, iarch, imach)
      && (ibfd->target_defaulted
	  || bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
    {
      if (bfd_get_arch (ibfd) == bfd_arch_unknown)
        printf
          ("non-fatal: Unable to recognise the format of the input file\n");
      else
	printf("non-fatal: Output file cannot represent architecture `%s'\n",
               bfd_printable_arch_mach (bfd_get_arch (ibfd),
                                        bfd_get_mach (ibfd)));
      return FALSE;
    }

  if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
    {
      printf("nonfatal error at line:%d\n", 204);
      return FALSE;
    }

  if (isympp)
    free (isympp);

  if (osympp != isympp)
    free (osympp);

  isympp = NULL;
  osympp = NULL;

  symsize = bfd_get_symtab_upper_bound (ibfd);
  if (symsize < 0)
    {
      printf("nonfatal error at line:%d\n", 220);
      return FALSE;
    }

  osympp = isympp = (asymbol **) xmalloc (symsize);
  symcount = bfd_canonicalize_symtab (ibfd, isympp);
  if (symcount < 0)
    {
      printf("nonfatal error at line:%d\n", 228);
      return FALSE;
    }

  /* BFD mandates that all output sections be created and sizes set before
     any output is done.  Thus, we traverse all sections multiple times.  */
  bfd_map_over_sections (ibfd, setup_section, obfd);

  setup_bfd_headers (ibfd, obfd);

  if (add_sections != NULL)
    {
      struct section_add *padd;
      struct section_list *pset;

      for (padd = add_sections; padd != NULL; padd = padd->next)
	{
	  flagword flags;

	  pset = find_section_list (padd->name, FALSE);
	  if (pset != NULL)
	    pset->used = TRUE;

	  flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
	  if (pset != NULL && pset->set_flags)
	    flags = pset->flags | SEC_HAS_CONTENTS;

	  /* bfd_make_section_with_flags() does not return very helpful
	     error codes, so check for the most likely user error first.  */
	  if (bfd_get_section_by_name (obfd, padd->name))
	    {
	      printf("nonfatal error at line:%d\n", 259);
              printf("\tnonfatal: can't add section '%s'\n", padd->name);
	      return FALSE;
	    }
	  else
	    {
	      /* We use LINKER_CREATED here so that the backend hooks
	         will create any special section type information,
	         instead of presuming we know what we're doing merely
	         because we set the flags.  */
	      padd->section = bfd_make_section_with_flags
		(obfd, padd->name, flags | SEC_LINKER_CREATED);
	      if (padd->section == NULL)
		{
		  printf("nonfatal error at line:%d\n", 273);
                  printf("\tnonfatal: can't create section '%s'\n", padd->name);
		  return FALSE;
		}
	    }

	  if (! bfd_set_section_size (obfd, padd->section, padd->size))
	    {
	      printf("nonfatal error at line:%d\n", 281);
	      return FALSE;
	    }

	  if (pset != NULL)
	    {
	      if (pset->change_vma != CHANGE_IGNORE)
		if (! bfd_set_section_vma (obfd, padd->section,
					   pset->vma_val))
		  {
		    printf("nonfatal error at line:%d\n", 291);
		    return FALSE;
		  }

	      if (pset->change_lma != CHANGE_IGNORE)
		{
		  padd->section->lma = pset->lma_val;

		  if (! bfd_set_section_alignment
		      (obfd, padd->section,
		       bfd_section_alignment (obfd, padd->section)))
		    {
		      printf("nonfatal error at line:%d\n", 303);
		      return FALSE;
		    }
		}
	    }
	}
    }

  if (bfd_count_sections (obfd) != 0
      && (gap_fill_set || pad_to_set))
    {
      asection **set;
      unsigned int c, i;

      /* We must fill in gaps between the sections and/or we must pad
	 the last section to a specified address.  We do this by
	 grabbing a list of the sections, sorting them by VMA, and
	 increasing the section sizes as required to fill the gaps.
	 We write out the gap contents below.  */

      c = bfd_count_sections (obfd);
      osections = (asection **) xmalloc (c * sizeof (asection *));
      set = osections;
      bfd_map_over_sections (obfd, get_sections, &set);

      qsort (osections, c, sizeof (asection *), compare_section_lma);

      gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type));
      memset (gaps, 0, c * sizeof (bfd_size_type));

      if (gap_fill_set)
	{
	  for (i = 0; i < c - 1; i++)
	    {
	      flagword flags;
	      bfd_size_type size;
	      bfd_vma gap_start, gap_stop;

	      flags = bfd_get_section_flags (obfd, osections[i]);
	      if ((flags & SEC_HAS_CONTENTS) == 0
		  || (flags & SEC_LOAD) == 0)
		continue;

	      size = bfd_section_size (obfd, osections[i]);
	      gap_start = bfd_section_lma (obfd, osections[i]) + size;
	      gap_stop = bfd_section_lma (obfd, osections[i + 1]);
	      if (gap_start < gap_stop)
		{
		  if (! bfd_set_section_size (obfd, osections[i],
					      size + (gap_stop - gap_start)))
		    {
		      printf("nonfatal error at line:%d\n", 354);
                      printf("\tnonfatal: can't fill gap\n");
		      status = 1;
		      break;
		    }
		  gaps[i] = gap_stop - gap_start;
		  if (max_gap < gap_stop - gap_start)
		    max_gap = gap_stop - gap_start;
		}
	    }
	}

      if (pad_to_set)
	{
	  bfd_vma lma;
	  bfd_size_type size;

	  lma = bfd_section_lma (obfd, osections[c - 1]);
	  size = bfd_section_size (obfd, osections[c - 1]);
	  if (lma + size < pad_to)
	    {
	      if (! bfd_set_section_size (obfd, osections[c - 1],
					  pad_to - lma))
		{
		  printf("nonfatal error at line:%d\n", 378);
                      printf("\tnonfatal: can't add padding\n");
		  status = 1;
		}
	      else
		{
		  gaps[c - 1] = pad_to - (lma + size);
		  if (max_gap < pad_to - (lma + size))
		    max_gap = pad_to - (lma + size);
		}
	    }
	}
    }

  bfd_set_symtab (obfd, osympp, symcount);

  /* This has to happen after the symbol table has been set.  */
  bfd_map_over_sections (ibfd, copy_section, obfd);

  if (add_sections != NULL)
    {
      struct section_add *padd;

      for (padd = add_sections; padd != NULL; padd = padd->next)
	{
	  if (! bfd_set_section_contents (obfd, padd->section, padd->contents,
					  0, padd->size))
	    {
	      printf("nonfatal error at line:%d\n", 421);
	      return FALSE;
	    }
	}
    }

  if (gap_fill_set || pad_to_set)
    {
      bfd_byte *buf;
      int c, i;

      /* Fill in the gaps.  */
      if (max_gap > 8192)
	max_gap = 8192;
      buf = (bfd_byte *) xmalloc (max_gap);
      memset (buf, gap_fill, max_gap);

      c = bfd_count_sections (obfd);
      for (i = 0; i < c; i++)
	{
	  if (gaps[i] != 0)
	    {
	      bfd_size_type left;
	      file_ptr off;

	      left = gaps[i];
	      off = bfd_section_size (obfd, osections[i]) - left;

	      while (left > 0)
		{
		  bfd_size_type now;

		  if (left > 8192)
		    now = 8192;
		  else
		    now = left;

		  if (! bfd_set_section_contents (obfd, osections[i], buf,
						  off, now))
		    {
		      printf("nonfatal error at line:%d\n", 461);
		      return FALSE;
		    }

		  left -= now;
		  off += now;
		}
	    }
	}
    }

  /* Allow the BFD backend to copy any private data it understands
     from the input BFD to the output BFD.  This is done last to
     permit the routine to look at the filtered symbol table, which is
     important for the ECOFF code at least.  */
  if (! bfd_copy_private_bfd_data (ibfd, obfd))
    {
      printf("nonfatal error at line:%d\n", 478);
      printf("\tnonfatal: error copying private BFD data\n");
      return FALSE;
    }

  return TRUE;
}

/* Create a section in OBFD with the same
   name and attributes as ISECTION in IBFD.  */
static void
setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
  bfd *obfd = (bfd *) obfdarg;
  struct section_list *p;
  sec_ptr osection;
  bfd_size_type size;
  bfd_vma vma;
  bfd_vma lma;
  flagword flags;
  const char *err;
  const char * name;
  char *prefix = NULL;
  bfd_boolean make_nobits;

  p = find_section_list (bfd_section_name (ibfd, isection), FALSE);
  if (p != NULL)
    p->used = TRUE;

  /* Get the, possibly new, name of the output section.  */
  name = find_section_rename (ibfd, isection, & flags);

  /* Prefix sections.  */
  if ((prefix_alloc_sections_string)
      && (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC))
    prefix = prefix_alloc_sections_string;
  else if (prefix_sections_string)
    prefix = prefix_sections_string;

  if (prefix)
    {
      char *n;

      n = (char *) xmalloc (strlen (prefix) + strlen (name) + 1);
      strcpy (n, prefix);
      strcat (n, name);
      name = n;
    }

  make_nobits = FALSE;
  if (p != NULL && p->set_flags)
    flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));

  osection = bfd_make_section_anyway_with_flags (obfd, name, flags);

  if (osection == NULL)
    {
      printf("failed to create output section\n");
      goto loser;
    }

  if (make_nobits)
    elf_section_type (osection) = SHT_NOBITS;

  size = bfd_section_size (ibfd, isection);

  if (! bfd_set_section_size (obfd, osection, size))
    {
      printf("failed to set size\n");
      goto loser;
    }

  vma = bfd_section_vma (ibfd, isection);
  if (p != NULL && p->change_vma == CHANGE_MODIFY)
    vma += p->vma_val;
  else if (p != NULL && p->change_vma == CHANGE_SET)
    vma = p->vma_val;
  else
    vma += change_section_address;

  if (! bfd_set_section_vma (obfd, osection, vma))
    {
      printf("failed to set vma\n");
      goto loser;
    }

  lma = isection->lma;
  if ((p != NULL) && p->change_lma != CHANGE_IGNORE)
    {
      if (p->change_lma == CHANGE_MODIFY)
	lma += p->lma_val;
      else if (p->change_lma == CHANGE_SET)
	lma = p->lma_val;
      else
	abort ();
    }
  else
    lma += change_section_address;

  osection->lma = lma;

  /* FIXME: This is probably not enough.  If we change the LMA we
     may have to recompute the header for the file as well.  */
  if (!bfd_set_section_alignment (obfd,
				  osection,
				  bfd_section_alignment (ibfd, isection)))
    {
      printf("failed to set alignment\n");
      goto loser;
    }

  /* Copy merge entity size.  */
  osection->entsize = isection->entsize;

  /* This used to be mangle_section; we do here to avoid using
     bfd_get_section_by_name since some formats allow multiple
     sections with the same name.  */
  isection->output_section = osection;
  isection->output_offset = 0;

  if ((isection->flags & SEC_GROUP) != 0)
    {
      asymbol *gsym = group_signature (isection);

      if (gsym != NULL)
	{
	  gsym->flags |= BSF_KEEP;
	  if (ibfd->xvec->flavour == bfd_target_elf_flavour)
	    elf_group_id (isection) = gsym;
	}
    }

  /* Allow the BFD backend to copy any private data it understands
     from the input section to the output section.  */
  if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
    {
      printf("failed to copy private data\n");
      goto loser;
    }

  /* All went well.  */
  return;

 loser:
  status = 1;
  printf("nonfatal error at line:%d\n", 626);
}

/* Once each of the sections is copied, we may still need to do some
   finalization work for private section headers.  Do that here.  */
static void
setup_bfd_headers (bfd *ibfd, bfd *obfd)
{
  /* Allow the BFD backend to copy any private data it understands
     from the input section to the output section.  */
  if (! bfd_copy_private_header_data (ibfd, obfd))
    {
      status = 1;
      printf("error in private header data\n");
      return;
    }

  /* All went well.  */
  return;
}

/* Copy the data of input section ISECTION of IBFD
   to an output section with the same name in OBFD.
   If stripping then don't copy any relocation info.  */
static void
copy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
{
  bfd *obfd = (bfd *) obfdarg;
  struct section_list *p;
  arelent **relpp;
  long relcount;
  sec_ptr osection;
  bfd_size_type size;
  long relsize;
  flagword flags;

  /* If we have already failed earlier on,
     do not keep on generating complaints now.  */
  if (status != 0)
    return;

  flags = bfd_get_section_flags (ibfd, isection);
  if ((flags & SEC_GROUP) != 0)
    return;

  osection = isection->output_section;
  size = bfd_get_section_size (isection);

  if (size == 0 || osection == 0)
    return;

  p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);

  /* Core files do not need to be relocated.  */
  if (bfd_get_format (obfd) == bfd_core)
    relsize = 0;
  else
    {
      relsize = bfd_get_reloc_upper_bound (ibfd, isection);

      if (relsize < 0)
	{
	  /* Do not complain if the target does not support relocations.  */
	  if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation)
	    relsize = 0;
	  else
	    {
	      status = 1;
	      printf("nonfatal error at line:%d\n", 679);
	      return;
	    }
	}
    }

  if (relsize == 0)
    bfd_set_reloc (obfd, osection, NULL, 0);
  else
    {
      relpp = (arelent **) xmalloc (relsize);
      relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
      if (relcount < 0)
	{
	  status = 1;
	  printf("nonfatal error at line:%d\n", 694);
          printf("\tnonfatal: relocation count is negative\n");
	  return;
	}

      bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
      if (relcount == 0)
	free (relpp);
    }

  if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
      && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
    {
      bfd_byte *memhunk = NULL;

      if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
	{
	  status = 1;
	  printf("nonfatal error at line:%d\n", 712);
	  return;
	}

      if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
	{
	  status = 1;
	  printf("nonfatal error at line:%d\n", 719);
	  return;
	}
      free (memhunk);
    }
  else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0)
    {
      void *memhunk = xmalloc (size);

      /* We don't permit the user to turn off the SEC_HAS_CONTENTS
	 flag--they can just remove the section entirely and add it
	 back again.  However, we do permit them to turn on the
	 SEC_HAS_CONTENTS flag, and take it to mean that the section
	 contents should be zeroed out.  */

      memset (memhunk, 0, size);
      if (! bfd_set_section_contents (obfd, osection, memhunk, 0, size))
	{
	  status = 1;
	  printf("nonfatal error at line:%d\n", 738);
	  return;
	}
      free (memhunk);
    }
}

/* Get all the sections.  This is used when --gap-fill or --pad-to is used.  */
static void
get_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg)
{
  asection ***secppp = (asection ***) secppparg;

  **secppp = osection;
  ++(*secppp);
}

/* Sort sections by VMA.  This is called via qsort, and is used when
   --gap-fill or --pad-to is used.  We force non loadable or empty
   sections to the front, where they are easier to ignore.  */
static int
compare_section_lma (const void *arg1, const void *arg2)
{
  const asection *const *sec1 = (const asection * const *) arg1;
  const asection *const *sec2 = (const asection * const *) arg2;
  flagword flags1, flags2;

  /* Sort non loadable sections to the front.  */
  flags1 = (*sec1)->flags;
  flags2 = (*sec2)->flags;
  if ((flags1 & SEC_HAS_CONTENTS) == 0
      || (flags1 & SEC_LOAD) == 0)
    {
      if ((flags2 & SEC_HAS_CONTENTS) != 0
	  && (flags2 & SEC_LOAD) != 0)
	return -1;
    }
  else
    {
      if ((flags2 & SEC_HAS_CONTENTS) == 0
	  || (flags2 & SEC_LOAD) == 0)
	return 1;
    }

  /* Sort sections by LMA.  */
  if ((*sec1)->lma > (*sec2)->lma)
    return 1;
  else if ((*sec1)->lma < (*sec2)->lma)
    return -1;

  /* Sort sections with the same LMA by size.  */
  if (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2))
    return 1;
  else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2))
    return -1;

  return 0;
}

/* Check the section rename list for a new name of the input section
   ISECTION.  Return the new name if one is found.
   Also set RETURNED_FLAGS to the flags to be used for this section.  */
static const char *
find_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
		     flagword * returned_flags)
{
  const char * old_name = bfd_section_name (ibfd, isection);
  section_rename * srename;

  /* Default to using the flags of the input section.  */
  * returned_flags = bfd_get_section_flags (ibfd, isection);

  for (srename = section_rename_list; srename != NULL; srename = srename->next)
    if (strcmp (srename->old_name, old_name) == 0)
      {
	if (srename->flags != (flagword) -1)
	  * returned_flags = srename->flags;

	return srename->new_name;
      }

  return old_name;
}

/* Return a pointer to the symbol used as a signature for GROUP.  */
static asymbol * group_signature (asection *group) {
  bfd *abfd = group->owner;
  Elf_Internal_Shdr *ghdr;

  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
    return NULL;

  ghdr = &elf_section_data (group)->this_hdr;
  if (ghdr->sh_link < elf_numsections (abfd))
    {
      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
      Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];

      if (symhdr->sh_type == SHT_SYMTAB
	  && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
	return isympp[ghdr->sh_info - 1];
    }
  return NULL;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]