Subject: ELF prebinding, round 1
To: None <tech-userlevel@netbsd.org>
From: Bang Jun-Young <junyoung@mogua.com>
List: tech-userlevel
Date: 09/04/2002 11:55:48
Hi,

I managed to modify ld and bfd so that they insert .pgot section in
executables. After that I have updated /usr/bin and has no problem
yet. A screenshot is here :-) : 

$ readelf -S /usr/bin/ld | grep got
  [ 6] .rel.got          REL             08049874 001874 000048 08   A  4  13  4
  [19] .got              PROGBITS        080810c8 0380c8 000218 04  WA  0   0  4
  [20] .pgot             PROGBITS        080812e0 0382e0 000218 04  WA  0   0  4

I'm attaching the patch at the end of this mail. I'm not a toolchain
expert, so not sure if it's technically correct. Could anybody have a
look at it and give me comments? [Note: most part of it is i386 specific;
any efforts to apply it to other platforms are left to those who are
using them.] 

Next round:
 - Copy contents of .got to .pgot at the final stage of linking.
 - Add a checksum section to check if existing libraries are different
   than needed libraries in dynamic section. I'm considering making 
   use of PE checksum routine which is already in bfd. Any better
   method? 
 
Jun-Young

-- 
Bang Jun-Young <junyoung@mogua.com>


Index: scripttempl/elf.sc
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/ld/scripttempl/elf.sc,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 elf.sc
--- ld/scripttempl/elf.sc	2001/04/23 12:29:24	1.1.1.3
+++ ld/scripttempl/elf.sc	2002/09/04 02:15:39
@@ -313,6 +313,7 @@
   ${DATA_PLT+${PLT}}
   ${RELOCATING+${OTHER_GOT_SYMBOLS}}
   .got		${RELOCATING-0} : { *(.got.plt) *(.got) }
+  .pgot		${RELOCATING-0} : { *(.pgot) }
   ${CREATE_SHLIB+${SDATA2}}
   ${CREATE_SHLIB+${SBSS2}}
   ${TEXT_DYNAMIC-${DYNAMIC}}


Index: elf32-i386.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/bfd/elf32-i386.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 elf32-i386.c
--- bfd/elf32-i386.c	2001/08/14 02:49:53	1.1.1.4
+++ bfd/elf32-i386.c	2002/09/04 02:10:01
@@ -478,6 +478,7 @@
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *sgot;
+  asection *spgot;
   asection *srelgot;
   asection *sreloc;
 
@@ -490,6 +491,7 @@
   local_got_refcounts = elf_local_got_refcounts (abfd);
 
   sgot = NULL;
+  spgot = NULL;
   srelgot = NULL;
   sreloc = NULL;
 
@@ -549,6 +551,12 @@
 	      BFD_ASSERT (sgot != NULL);
 	    }
 
+	  if (spgot == NULL)
+	    {
+	      spgot = bfd_get_section_by_name (dynobj, ".pgot");
+	      BFD_ASSERT (spgot != NULL);
+	    }
+
 	  if (srelgot == NULL
 	      && (h != NULL || info->shared))
 	    {
@@ -583,6 +591,7 @@
 		    }
 
 		  sgot->_raw_size += 4;
+		  spgot->_raw_size += 4;
 		  srelgot->_raw_size += sizeof (Elf32_External_Rel);
 		}
 	      else
@@ -608,6 +617,7 @@
 		  local_got_refcounts[r_symndx] = 1;
 
 		  sgot->_raw_size += 4;
+		  spgot->_raw_size += 4;
 		  if (info->shared)
 		    {
 		      /* If we are generating a shared object, we need to
@@ -844,6 +854,7 @@
   struct elf_link_hash_entry *h;
   bfd *dynobj;
   asection *sgot;
+  asection *spgot;
   asection *srelgot;
 
   symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
@@ -855,6 +866,7 @@
     return true;
 
   sgot = bfd_get_section_by_name (dynobj, ".got");
+  spgot = bfd_get_section_by_name (dynobj, ".pgot");
   srelgot = bfd_get_section_by_name (dynobj, ".rel.got");
 
   relend = relocs + sec->reloc_count;
@@ -874,6 +886,7 @@
 		if (h->got.refcount == 0)
 		  {
 		    sgot->_raw_size -= 4;
+		    spgot->_raw_size -= 4;
 		    srelgot->_raw_size -= sizeof (Elf32_External_Rel);
 		  }
 	      }
@@ -886,6 +899,7 @@
 		if (local_got_refcounts[r_symndx] == 0)
 		  {
 		    sgot->_raw_size -= 4;
+		    spgot->_raw_size -= 4;
 		    if (info->shared)
 		      srelgot->_raw_size -= sizeof (Elf32_External_Rel);
 		  }
@@ -922,7 +936,7 @@
      struct elf_link_hash_entry *h;
 {
   bfd *dynobj;
-  asection *s;
+  asection *s, *s1;
   unsigned int power_of_two;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -997,6 +1011,10 @@
       BFD_ASSERT (s != NULL);
       s->_raw_size += 4;
 
+      s1 = bfd_get_section_by_name (dynobj, ".pgot");
+      BFD_ASSERT (s1 != NULL);
+      s1->_raw_size += 4;
+
       /* We also need to make an entry in the .rel.plt section.  */
       s = bfd_get_section_by_name (dynobj, ".rel.plt");
       BFD_ASSERT (s != NULL);
@@ -1212,7 +1230,8 @@
 	      s->reloc_count = 0;
 	    }
 	}
-      else if (strncmp (name, ".got", 4) != 0)
+      else if (strncmp (name, ".got", 4) != 0 &&
+      	       strncmp (name, ".pgot", 5) != 0)
 	{
 	  /* It's not one of our sections, so don't allocate space.  */
 	  continue;
@@ -1964,12 +1983,15 @@
 {
   bfd *dynobj;
   asection *sgot;
+  asection *spgot;
   asection *sdyn;
 
   dynobj = elf_hash_table (info)->dynobj;
 
   sgot = bfd_get_section_by_name (dynobj, ".got.plt");
   BFD_ASSERT (sgot != NULL);
+  spgot = bfd_get_section_by_name (dynobj, ".pgot");
+  BFD_ASSERT (spgot != NULL);
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -2076,6 +2098,7 @@
     }
 
   elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+  elf_section_data (spgot->output_section)->this_hdr.sh_entsize = 4;
 
   return true;
 }
Index: elflink.c
===================================================================
RCS file: /cvsroot/gnusrc/gnu/dist/toolchain/bfd/elflink.c,v
retrieving revision 1.1.1.4
diff -u -r1.1.1.4 elflink.c
--- bfd/elflink.c	2001/08/14 02:50:04	1.1.1.4
+++ bfd/elflink.c	2002/09/04 02:10:01
@@ -31,7 +31,7 @@
      struct bfd_link_info *info;
 {
   flagword flags;
-  register asection *s;
+  register asection *s, *s1;
   struct elf_link_hash_entry *h;
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   int ptralign;
@@ -73,6 +73,12 @@
 	return false;
     }
 
+  s1 = bfd_make_section (abfd, ".pgot");
+  if (s1 == NULL
+      || !bfd_set_section_flags (abfd, s1, flags)
+      || !bfd_set_section_alignment (abfd, s1, ptralign))
+    return false;
+
   /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the .got
      (or .got.plt) section.  We don't do this in the linker script
      because we don't want to define the symbol if we are not creating
@@ -94,6 +100,7 @@
 
   /* The first bit of the global offset table is the header.  */
   s->_raw_size += bed->got_header_size + bed->got_symbol_offset;
+  s1->_raw_size = s->_raw_size;
 
   return true;
 }