]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Add .got.plt handling. Fix R_386_GOT32 relocations for static binaries.
authorUlrich Drepper <drepper@redhat.com>
Tue, 22 Jan 2008 15:49:39 +0000 (15:49 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 22 Jan 2008 15:49:39 +0000 (15:49 +0000)
src/ChangeLog
src/elf32-i386.script
src/i386_ld.c
src/ld.h
src/ldgeneric.c

index 006b0582f4495a73cb1f5898b20e0c835a1bdb8b..5b2d0c12887df49cb1e83e9fc35f522cb62a28f4 100644 (file)
@@ -1,3 +1,27 @@
+2008-01-22  Ulrich Drepper  <drepper@redhat.com>
+
+       * ld.h (struct callbacks): Add initialize_gotplt.
+       (struct scnhead): Add scn_dot_gotplt.
+       (struct ld_state): Add gotpltscnidx.
+       * i386_ld.c (elf_i386_initialize_plt): Minor optimization.
+       (elf_i386_initialize_pltrel): Likewise.
+       (elf_i386_initialize_got): There is now a separate .got.plt, so
+       don't do the PLT-related work here.  Initialize d_type.
+       (elf_i386_initialize_gotplt): New function.
+       (elf_i386_plt0): Use ud2a after indirect jump.
+       (elf_i386_pic_plt0_entry): Likewise.
+       (elf_i386_finalize_plt): Reference now .got.plt.
+       (elf_i386_count_relocations): For GOT entries which need no relocation
+       don't bump nrel_got.
+       (elf_i386_create_relocations): Also get .got.plt.  Rewrite R-386_GOT32
+       handling for split .got/.got.plt.
+       (elf_i386_ld_init): Initialize callbacks.initialize_gotplt.
+       * elf32-i386.script: Sort sections for security.  There are no .got
+       input sections.  Add .got.plt.
+       * ldgeneric.c (ld_generic_generate_sections): Add .got.plt section.
+       (ld_generic_create_outfile): Initialize .got.plt section.
+       Use .got.plt address for _GLOBAL_OFFSET_TABLE_ symbol and DT_PLTGOT.
+
 2008-01-19  Ulrich Drepper  <drepper@redhat.com>
 
        * i386_ld.c (elf_i386_count_relocations): PLT relocations for undefined
index d62333acac0e644db77c3f1bcfffe46c22fca9ae..0e5905b612a9cbedbeee09ea3e34b0c46373b941 100644 (file)
@@ -85,13 +85,6 @@ SEGMENT [RW]
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
   . = ALIGN(PAGESIZE) + (. & (PAGESIZE - 1));
-  .data
-    {
-      *(.data)
-      *(.data.*)
-      *(.gnu.linkonce.d.*)
-    }
-  .data1;
   .eh_frame
     {
       KEEP (*(.eh_frame))
@@ -125,15 +118,19 @@ SEGMENT [RW]
       KEEP (*(.dtors))
     }
   .jcr;
-  .got
+  .dynamic;
+  .got;
+  .got.plt;
+  .data
     {
-      *(.got.plt)
-      *(.got)
+      *(.data)
+      *(.data.*)
+      *(.gnu.linkonce.d.*)
     }
-  .dynamic;
   /* We want the small data sections together, so single-instruction offsets
      can access them all, and initialized data all before uninitialized, so
      we can shorten the on-disk segment size.  */
+  .data1;
   .sdata
     {
       *(.sdata)
index 82fb9473e1fb4b4ade89c45088e529804abcc151..029e939d268ce149c77f59c42f66325f798ee087 100644 (file)
@@ -214,8 +214,9 @@ elf_i386_initialize_plt (struct ld_state *statep, Elf_Scn *scn)
      relocation routines) and one for each function we call in a DSO.  */
   data->d_size = (1 + statep->nplt) * PLT_ENTRY_SIZE;
   data->d_buf = xcalloc (1, data->d_size);
-  data->d_align = 8;
+  assert (data->d_type == ELF_T_BYTE);
   data->d_off = 0;
+  data->d_align = 8;
 
   statep->nplt_used = 1;
 }
@@ -232,9 +233,10 @@ elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn)
           elf_errmsg (-1));
 
   /* One relocation per PLT entry.  */
-  data->d_size = statep->nplt * sizeof (Elf32_Rel);
-  data->d_buf = xcalloc (1, data->d_size);
+  size_t size = statep->nplt * sizeof (Elf32_Rel);
+  data->d_buf = xcalloc (1, size);
   data->d_type = ELF_T_REL;
+  data->d_size = size;
   data->d_align = 4;
   data->d_off = 0;
 }
@@ -243,26 +245,45 @@ elf_i386_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn)
 static void
 elf_i386_initialize_got (struct ld_state *statep, Elf_Scn *scn)
 {
-  Elf_Data *data;
-
-  /* If we have no .plt we don't need the special entries we normally
-     create for it.  The other contents is created later.  */
-  if (statep->ngot + statep->nplt == 0)
-    return;
+  /* If we come here we better need a GOT.  */
+  assert (statep->ngot != 0);
 
-  data = elf_newdata (scn);
+  Elf_Data *data = elf_newdata (scn);
   if (data == NULL)
     error (EXIT_FAILURE, 0, gettext ("cannot allocate GOT section: %s"),
           elf_errmsg (-1));
 
-  /* We construct the .got section in pieces.  Here we only add the data
+  /* Just a single word per GOT entry is needed.  */
+  size_t size = statep->ngot * sizeof (Elf32_Addr);
+  data->d_buf = xcalloc (1, size);
+  data->d_size = size;
+  data->d_type = ELF_T_WORD;
+  data->d_off = 0;
+  data->d_align = sizeof (Elf32_Addr);
+}
+
+
+static void
+elf_i386_initialize_gotplt (struct ld_state *statep, Elf_Scn *scn)
+{
+  /* If we come here we better need a PLT.  */
+  assert (statep->nplt != 0);
+
+  Elf_Data *data = elf_newdata (scn);
+  if (data == NULL)
+    error (EXIT_FAILURE, 0, gettext ("cannot allocate GOTPLT section: %s"),
+          elf_errmsg (-1));
+
+  /* We construct the .got.plt section in pieces.  Here we only add the data
      structures which are used by the PLT.  This includes three reserved
      entries at the beginning (the first will contain a pointer to the
      .dynamic section), and one word for each PLT entry.  */
-  data->d_size = (3 + statep->ngot + statep->nplt) * sizeof (Elf32_Addr);
-  data->d_buf = xcalloc (1, data->d_size);
-  data->d_align = sizeof (Elf32_Addr);
+  size_t size = (3 + statep->nplt) * sizeof (Elf32_Addr);
+  data->d_buf = xcalloc (1, size);
+  data->d_type = ELF_T_WORD;
+  data->d_size = size;
   data->d_off = 0;
+  data->d_align = sizeof (Elf32_Addr);
 }
 
 
@@ -274,7 +295,8 @@ static const unsigned char elf_i386_plt0_entry[PLT_ENTRY_SIZE] =
   0, 0, 0, 0,  /* replaced with address of .got + 4.  */
   0xff, 0x25,  /* jmp indirect */
   0, 0, 0, 0,  /* replaced with address of .got + 8.  */
-  0, 0, 0, 0   /* pad out to 16 bytes.  */
+  0x0f, 0x0b,  /* ud2a, to prevent further decoding.  */
+  0, 0         /* pad out to 16 bytes.  */
 };
 
 /* Type describing the first PLT entry in non-PIC.  */
@@ -295,7 +317,8 @@ static const unsigned char elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] =
 {
   0xff, 0xb3, 4, 0, 0, 0,      /* pushl 4(%ebx) */
   0xff, 0xa3, 8, 0, 0, 0,      /* jmp *8(%ebx) */
-  0, 0, 0, 0                   /* pad out to 16 bytes.  */
+  0x0f, 0x0b,                  /* ud2a, to prevent further decoding.  */
+  0, 0                         /* pad out to 16 bytes.  */
 };
 
 /* Contents of all but the first PLT entry in executable.  */
@@ -352,23 +375,24 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
     return;
 
   /* Get the address of the got section.  */
-  scn = elf_getscn (statep->outelf, statep->gotscnidx);
+  scn = elf_getscn (statep->outelf, statep->gotpltscnidx);
   xelf_getshdr (scn, shdr);
   data = elf_getdata (scn, NULL);
   assert (shdr != NULL && data != NULL);
   Elf32_Addr gotaddr = shdr->sh_addr;
 
-  /* Now create the initial values for the .got section.  The first
-     word contains the address of the .dynamic section.  */
+  /* Now create the initial values for the .got.plt section.  The
+     first word contains the address of the .dynamic section.  The
+     second and third entry are left empty for use by the dynamic
+     linker.  The following entries are pointers to the instructions
+     following the initial jmp instruction in the corresponding PLT
+     entry.  */
   xelf_getshdr (elf_getscn (statep->outelf, statep->dynamicscnidx), shdr);
   assert (shdr != NULL);
   ((Elf32_Word *) data->d_buf)[0] = shdr->sh_addr;
 
-  /* The second and third entry are left empty for use by the dynamic
-     linker.  The following entries are pointers to the instructions
-     following the initial jmp instruction in the corresponding PLT
-     entry.  Since the first PLT entry is special the first used one
-     has the index 1.  */
+  /* The PLT contains code which a user of a function jumps to.  The first
+     PLT entry is special, so the first used one has the index 1.  */
   scn = elf_getscn (statep->outelf, statep->pltscnidx);
   xelf_getshdr (scn, shdr);
   assert (shdr != NULL);
@@ -394,7 +418,6 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
       /* Point the GOT entry at the PLT entry, after the initial jmp.  */
       ((Elf32_Word *) data->d_buf)[3 + cnt] = pltentryaddr + 6;
 
-
       /* If the symbol is defined, adjust the address.  */
       if (((Elf32_Sym *) dynsymdata->d_buf)[1 + cnt].st_shndx != SHN_UNDEF)
        {
@@ -458,7 +481,7 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
     }
 
   /* Create the .rel.plt section data.  It simply means relocations
-     addressing the corresponding entry in the .got section.  The
+     addressing the corresponding entry in the .got.plt section.  The
      section name is misleading.  */
   scn = elf_getscn (statep->outelf, statep->pltrelscnidx);
   xelf_getshdr (scn, shdr);
@@ -466,12 +489,12 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
   assert (shdr != NULL && data != NULL);
 
   /* Update the sh_link to point to the section being modified.  We
-     point it here (correctly) to the .got section.  Some linkers
+     point it here (correctly) to the .got.plt section.  Some linkers
      (e.g., the GNU binutils linker) point to the .plt section.  This
      is wrong since the .plt section isn't modified even though the
      name .rel.plt suggests that this is correct.  */
   shdr->sh_link = statep->dynsymscnidx;
-  shdr->sh_info = statep->gotscnidx;
+  shdr->sh_info = statep->gotpltscnidx;
   (void) xelf_update_shdr (scn, shdr);
 
   for (cnt = 0; cnt < statep->nplt; ++cnt)
@@ -482,7 +505,7 @@ elf_i386_finalize_plt (struct ld_state *statep, size_t nsym,
       xelf_getrel_ptr (data, cnt, rel);
       rel->r_offset = gotaddr + (3 + cnt) * sizeof (Elf32_Addr);
       /* The symbol table entries for the functions from DSOs are at
-        the end of the symbol table.  */
+        the beginning of the symbol table.  */
       rel->r_info = XELF_R_INFO (1 + cnt, R_386_JMP_SLOT);
       (void) xelf_update_rel (data, cnt, rel);
     }
@@ -533,13 +556,16 @@ elf_i386_count_relocations (struct ld_state *statep, struct scninfo *scninfo)
            {
            case R_386_GOT32:
              if (! scninfo->fileinfo->symref[r_sym]->defined
-                 || scninfo->fileinfo->symref[r_sym]->in_dso)
-               relsize += sizeof (Elf32_Rel);
+                 || scninfo->fileinfo->symref[r_sym]->in_dso
+                 || statep->file_type == dso_file_type)
+               {
+                 relsize += sizeof (Elf32_Rel);
+                 ++statep->nrel_got;
+               }
 
-             /* This relocation is not emitted in the output file but
-                requires a GOT entry.  */
+             /* Even if this relocation is not emitted in the output
+                file it requires a GOT entry.  */
              ++statep->ngot;
-             ++statep->nrel_got;
 
              /* FALLTHROUGH */
 
@@ -668,15 +694,25 @@ elf_i386_create_relocations (struct ld_state *statep,
   Elf32_Addr pltaddr = shdr->sh_addr;
 
   Elf_Scn *gotscn = elf_getscn (statep->outelf, statep->gotscnidx);
-  shdr = elf32_getshdr (gotscn);
+  // XXX Adjust the address, if necessary, for relro
+  Elf_Data *gotdata = NULL;
+  if (statep->need_got)
+    {
+      gotdata = elf_getdata (gotscn, NULL);
+      assert (gotdata != NULL);
+    }
+
+  Elf_Scn *gotpltscn = elf_getscn (statep->outelf, statep->gotpltscnidx);
+  shdr = elf32_getshdr (gotpltscn);
   assert (shdr != NULL);
   Elf32_Addr gotaddr = shdr->sh_addr;
 
   Elf_Scn *reldynscn = elf_getscn (statep->outelf, statep->reldynscnidx);
   Elf_Data *reldyndata = elf_getdata (reldynscn, NULL);
+  assert (reldyndata != NULL);
 
   size_t nreldyn = 0;
-#define ngot_used (3 + statep->nplt + nreldyn)
+  size_t ngotconst = statep->nrel_got;
 
   struct scninfo *first = statep->rellist->next;
   struct scninfo *runp = first;
@@ -686,7 +722,7 @@ elf_i386_create_relocations (struct ld_state *statep,
       Elf_Data *reldata = elf_getdata (runp->scn, NULL);
       int nrels = rshdr->sh_size / rshdr->sh_entsize;
 
-      /* We will need the following vlaues a couple of times.  Help
+      /* We will need the following values a couple of times.  Help
         the compiler and improve readability.  */
       struct symbol **symref = runp->fileinfo->symref;
       struct scninfo *scninfo = runp->fileinfo->scninfo;
@@ -720,7 +756,7 @@ elf_i386_create_relocations (struct ld_state *statep,
              XElf_Sym_vardef (sym);
              xelf_getsym (symdata, idx, sym);
 
-             /* The value just depends on the position of the referenced
+             /* The value only depends on the position of the referenced
                 section in the output file and the addend.  */
              value = scninfo[sym->st_shndx].offset + sym->st_value;
            }
@@ -730,22 +766,20 @@ elf_i386_create_relocations (struct ld_state *statep,
                /* Symbol in ignored COMDAT group section.  */
                continue;
 
+             value = symref[idx]->merge.value;
              if (symref[idx]->in_dso)
                {
-                 /* MERGE.VALUE contains the PLT index.  We have to
-                    add 1 since there is this one special PLT entry
-                    at the beginning.  */
-                 assert (symref[idx]->merge.value != 0
-                         || symref[idx]->type != STT_FUNC);
-                 value = pltaddr + symref[idx]->merge.value * PLT_ENTRY_SIZE;
+                 /* MERGE.VALUE contains the PLT index.  If this is not for
+                    a function the actual value will be computed later.  */
+                 assert (value != 0 || symref[idx]->type != STT_FUNC);
+                 value = pltaddr + value * PLT_ENTRY_SIZE;
                }
-             else
-               value = symref[idx]->merge.value;
            }
 
          /* Address of the relocated memory in the data buffer.  */
          void *relloc = (char *) data->d_buf + rel->r_offset;
 
+         uint32_t thisgotidx;
          switch (XELF_R_TYPE (rel->r_info))
            {
              /* These three cases can be handled together since the
@@ -781,6 +815,7 @@ elf_i386_create_relocations (struct ld_state *statep,
                        = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_COPY);
                      (void) xelf_update_rel (reldyndata, nreldyn, rel2);
                      ++nreldyn;
+                     assert (nreldyn <= statep->nrel_got);
 
                      /* Update the symbol table record for the new
                         address.  */
@@ -833,6 +868,7 @@ elf_i386_create_relocations (struct ld_state *statep,
                      = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_32);
                  (void) xelf_update_rel (reldyndata, nreldyn, rel2);
                  ++nreldyn;
+                 assert (nreldyn <= statep->nrel_got);
 
                  value = 0;
                }
@@ -840,19 +876,45 @@ elf_i386_create_relocations (struct ld_state *statep,
              break;
 
            case R_386_GOT32:
-             store_4ubyte_unaligned (relloc, ngot_used * sizeof (Elf32_Addr));
+             if (! symref[idx]->defined || symref[idx]->in_dso)
+               {
+                 thisgotidx = nreldyn++;
+                 assert (thisgotidx < statep->nrel_got);
 
-             /* Add a relocation to initialize the GOT entry.  */
+                 /* Add a relocation to initialize the GOT entry.  */
 #if NATIVE_ELF != 0
-             xelf_getrel_ptr (reldyndata, nreldyn, rel2);
+                 xelf_getrel_ptr (reldyndata, thisgotidx, rel2);
 #else
-             rel2 = &rel_mem;
+                 rel2 = &rel_mem;
 #endif
-             rel2->r_offset = gotaddr + ngot_used * sizeof (Elf32_Addr);
-             rel2->r_info
-               = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT);
-             (void) xelf_update_rel (reldyndata, nreldyn, rel2);
-             ++nreldyn;
+                 rel2->r_offset = gotaddr + ((thisgotidx - statep->ngot)
+                                             * sizeof (Elf32_Addr));
+                 rel2->r_info
+                   = XELF_R_INFO (symref[idx]->outdynsymidx, R_386_GLOB_DAT);
+                 (void) xelf_update_rel (reldyndata, thisgotidx, rel2);
+               }
+             else if (statep->file_type != dso_file_type)
+               {
+                 thisgotidx = ngotconst++;
+                 assert (thisgotidx < statep->ngot);
+
+                 /* We have to use a GOT since the generated code
+                    requires it but we know the address and therefore
+                    do not need a relocation.  */
+                 ((uint32_t *) gotdata->d_buf)[thisgotidx] = value;
+               }
+             else
+               {
+                 thisgotidx = nreldyn++;
+                 assert (thisgotidx < statep->nrel_got);
+
+                 // XXX generate a relative relocation.
+                 abort ();
+               }
+
+             store_4ubyte_unaligned (relloc,
+                                     (thisgotidx - statep->ngot)
+                                     * sizeof (Elf32_Addr));
              break;
 
            case R_386_GOTOFF:
@@ -882,7 +944,6 @@ elf_i386_create_relocations (struct ld_state *statep,
            case R_386_TLS_IE_32:
            case R_386_TLS_LE_32:
              // XXX For now fall through
- printf("ignored relocation %d\n", (int) XELF_R_TYPE (rel->r_info));
              break;
 
            case R_386_NONE:
@@ -919,6 +980,7 @@ elf_i386_ld_init (struct ld_state *statep)
   statep->callbacks.initialize_pltrel = elf_i386_initialize_pltrel;
 
   statep->callbacks.initialize_got = elf_i386_initialize_got;
+  statep->callbacks.initialize_gotplt = elf_i386_initialize_gotplt;
 
   statep->callbacks.finalize_plt = elf_i386_finalize_plt;
 
index bcf21f2cfb1ae5e4f465c10c8f4ce16db81cdc3d..5890e855f10b557dc8fe5cd31d02b9816cb7be62 100644 (file)
--- a/src/ld.h
+++ b/src/ld.h
@@ -406,6 +406,11 @@ struct callbacks
 #define INITIALIZE_GOT(state, scn) \
   DL_CALL_FCT ((state)->callbacks.initialize_got, (state, scn))
 
+  /* Create the data structures for the .got.plt section and initialize it.  */
+  void (*initialize_gotplt) (struct ld_state *, Elf_Scn *scn);
+#define INITIALIZE_GOTPLT(state, scn) \
+  DL_CALL_FCT ((state)->callbacks.initialize_gotplt, (state, scn))
+
   /* Return the tag corresponding to the native relocation type for
      the platform.  */
   int (*rel_type) (struct ld_state *);
@@ -670,6 +675,7 @@ struct scnhead
       scn_normal,              /* Section from the input file(s).  */
       scn_dot_interp,          /* Generated .interp section.  */
       scn_dot_got,             /* Generated .got section.  */
+      scn_dot_gotplt,          /* Generated .got.plt section.  */
       scn_dot_dynrel,          /* Generated .rel.dyn section.  */
       scn_dot_dynamic,         /* Generated .dynamic section.  */
       scn_dot_dynsym,          /* Generated .dynsym section.  */
@@ -937,6 +943,8 @@ struct ld_state
 
   /* Global offset table section.  */
   Elf32_Word gotscnidx;
+  /* And the part of the PLT.  */
+  Elf32_Word gotpltscnidx;
 
   /* This section will hole all non-PLT relocations.  */
   Elf32_Word reldynscnidx;
index 63fc77ca5ccacfdfaf9fc2424840030501243eb2..9a8ea8de84dca7aa739f71d259176dc707dcd282 100644 (file)
@@ -1280,7 +1280,7 @@ add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype)
                          || shdr->sh_type == SHT_FINI_ARRAY
                          || shdr->sh_type == SHT_PREINIT_ARRAY))
        {
-         /* Check whether the check needs to be executable.  */
+         /* Check whether the section needs to be executable.  */
          if (shdr->sh_type == SHT_PROGBITS
              && (shdr->sh_flags & SHF_EXECINSTR) == 0
              && strcmp (elf_strptr (fileinfo->elf, fileinfo->shstrndx,
@@ -2414,8 +2414,11 @@ ld_generic_generate_sections (struct ld_state *statep)
                             : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1),
                             xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));
 
-         /* This means we will also need the .got section.  */
-         ld_state.need_got = true;
+         /* XXX We might need a function which returns the section flags.  */
+         new_generated_scn (scn_dot_gotplt, ".got.plt", SHT_PROGBITS,
+                            SHF_ALLOC | SHF_WRITE,
+                            xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1),
+                            xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1));
 
          /* Mark all used DSOs as used.  Determine whether any referenced
             object uses symbol versioning.  */
@@ -3938,6 +3941,17 @@ ld_generic_create_outfile (struct ld_state *statep)
          continue;
        }
 
+      if (unlikely (head->kind == scn_dot_gotplt))
+       {
+         /* Remember the index of this section.  */
+         ld_state.gotpltscnidx = elf_ndxscn (scn);
+
+         /* Give the backend the change to initialize the section.  */
+         INITIALIZE_GOTPLT (&ld_state, scn);
+
+         continue;
+       }
+
       if (unlikely (head->kind == scn_dot_dynrel))
        {
          Elf_Data *outdata;
@@ -4592,7 +4606,8 @@ ld_generic_create_outfile (struct ld_state *statep)
   if (ld_state.got_symbol != NULL)
     {
       assert (nsym < nsym_allocated);
-      fillin_special_symbol (ld_state.got_symbol, ld_state.gotscnidx,
+      // XXX Fix so that it works even if no PLT is needed.
+      fillin_special_symbol (ld_state.got_symbol, ld_state.gotpltscnidx,
                             nsym++, symdata, strtab);
     }
 
@@ -6189,8 +6204,9 @@ internal error: nobits section follows nobits section"));
          /* Add the entries related to the .plt.  */
          if (ld_state.nplt > 0)
            {
-             xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.gotscnidx),
-                           shdr);
+             // XXX Make this work if there is no PLT
+             xelf_getshdr (elf_getscn (ld_state.outelf,
+                                       ld_state.gotpltscnidx), shdr);
              assert (shdr != NULL);
              new_dynamic_entry (dyndata, ld_state.ndynamic_filled++,
                                 // XXX This should probably be machine