This is the mail archive of the binutils@sources.redhat.com 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]

Fix PLT for x86-64



For x86-64 the PLT was totally broken, with the appended patch it
looks fine to me and should follow now the ABI:

Disassembly of section .plt:

0000000000003c78 <.plt>:
    3c78:       ff 35 7a 41 01 00       pushq  82298(%rip)        # 17df8 <_GLOBAL_OFFSET_TABLE_+0x8>
    3c7e:       ff 25 7c 41 01 00       jmpq   *82300(%rip)        # 17e00 <_GLOBAL_OFFSET_TABLE_+0x10>
    3c84:       90                      nop    
    3c85:       90                      nop    
    3c86:       90                      nop    
    3c87:       90                      nop    
    3c88:       ff 25 7a 41 01 00       jmpq   *82298(%rip)        # 17e08 <_GLOBAL_OFFSET_TABLE_+0x18>
    3c8e:       68 00 00 00 00          pushq  $0x0
    3c93:       e9 e0 ff ff ff          jmpq   3c78 <_start-0x658>
    3c98:       ff 25 72 41 01 00       jmpq   *82290(%rip)        # 17e10 <_GLOBAL_OFFSET_TABLE_+0x20>
    3c9e:       68 01 00 00 00          pushq  $0x1
    3ca3:       e9 d0 ff ff ff          jmpq   3c78 <_start-0x658>

I'll commit this later.  

Phil, should I add this also on the branch?  This patch is needed for
PIC on x86-64 but I'm not sure that it's the last problem.

Andreas

2001-04-19  Andreas Jaeger  <aj@suse.de>

	* elf64-x86-64.c (elf64_x86_64_plt0_entry): Fix instructions.
	(elf64_x86_64_plt_entry): Likewise.
	(elf64_x86_64_finish_dynamic_sections): Fix PLT0 generation.
	(elf64_x86_64_finish_dynamic_symbol): Fix PLT generation.

============================================================
Index: bfd/elf64-x86-64.c
--- bfd/elf64-x86-64.c	2001/03/07 13:49:11	1.11
+++ bfd/elf64-x86-64.c	2001/04/19 08:00:06
@@ -173,18 +173,18 @@
 
 static const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] =
 {
-  0xff, 0xb3, 8, 0, 0, 0,	/* pushq GOT+8(%rip) */
-  0xff, 0xa3, 16, 0, 0, 0,	/* jmp GOT+16(%rip) */
-  0, 0, 0, 0			/* pad out to 16 bytes.	 */
+  0xff, 0x35, 8, 0, 0, 0,	/* pushq GOT+8(%rip)  */
+  0xff, 0x25, 16, 0, 0, 0,	/* jmpq *GOT+16(%rip) */
+  0x90, 0x90, 0x90, 0x90	/* pad out to 16 bytes with nops.  */
 };
 
 /* Subsequent entries in a procedure linkage table look like this.  */
 
 static const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] =
 {
-  0xff, 0xa3,	/* jmp *name@GOTPC(%rip) */
+  0xff, 0x25,	/* jmpq *name@GOTPC(%rip) */
   0, 0, 0, 0,	/* replaced with offset to this symbol in .got.	 */
-  0x68,	/* pushq immediate */
+  0x68,		/* pushq immediate */
   0, 0, 0, 0,	/* replaced with index into relocation table.  */
   0xe9,		/* jmp relative */
   0, 0, 0, 0	/* replaced with offset to start of .plt0.  */
@@ -1664,13 +1664,26 @@
       /* Insert the relocation positions of the plt section.  The magic
 	 numbers at the end of the statements are the positions of the
 	 relocations in the plt section.  */
-      bfd_put_64 (output_bfd, got_offset, splt->contents + h->plt.offset + 2);
-      bfd_put_64 (output_bfd, plt_index * sizeof (Elf64_External_Rela),
+      /* Put offset for jmp *name@GOTPCREL(%rip), since the
+	 instruction uses 6 bytes, subtract this value.  */
+      bfd_put_32 (output_bfd,
+		      (sgot->output_section->vma
+		       + sgot->output_offset
+		       + got_offset
+		       - splt->output_section->vma
+		       - splt->output_offset
+		       - h->plt.offset
+		       - 6),
+		  splt->contents + h->plt.offset + 2);
+      /* Put relocation index.  */
+      bfd_put_32 (output_bfd, plt_index,
 		  splt->contents + h->plt.offset + 7);
-      bfd_put_64 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
+      /* Put offset for jmp .PLT0.  */
+      bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE),
 		  splt->contents + h->plt.offset + 12);
 
-      /* Fill in the entry in the global offset table.	*/
+      /* Fill in the entry in the global offset table, initially this
+	 points to the pushq instruction in the PLT which is at offset 6.  */
       bfd_put_64 (output_bfd, (splt->output_section->vma + splt->output_offset
 			       + h->plt.offset + 6),
 		  sgot->contents + got_offset);
@@ -1747,6 +1760,8 @@
 
   dynobj = elf_hash_table (info)->dynobj;
 
+  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
+  BFD_ASSERT (sgot != NULL);
   sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
 
   if (elf_hash_table (info)->dynamic_sections_created)
@@ -1816,7 +1831,29 @@
       BFD_ASSERT (splt != NULL);
       if (splt->_raw_size > 0)
 	{
+	  /* Fill in the first entry in the procedure linkage table.  */
 	  memcpy (splt->contents, elf64_x86_64_plt0_entry, PLT_ENTRY_SIZE);
+	  /* Add offset for pushq GOT+8(%rip), since the instruction
+	     uses 6 bytes subtract this value.  */
+	  bfd_put_32 (output_bfd,
+		      (sgot->output_section->vma
+		       + sgot->output_offset
+		       + 8
+		       - splt->output_section->vma
+		       - splt->output_offset
+		       - 6),
+		      splt->contents + 2);
+	  /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to
+	     the end of the instruction.  */
+	  bfd_put_32 (output_bfd,
+		      (sgot->output_section->vma
+		       + sgot->output_offset
+		       + 16
+		       - splt->output_section->vma
+		       - splt->output_offset
+		       - 12),
+		      splt->contents + 8);
+	  
 	}
 
       elf_section_data (splt->output_section)->this_hdr.sh_entsize =
@@ -1825,8 +1862,6 @@
 
   /* Set the first entry in the global offset table to the address of
      the dynamic section.  */
-  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
-  BFD_ASSERT (sgot != NULL);
   if (sgot->_raw_size > 0)
     {
       if (sdyn == NULL)
@@ -1835,7 +1870,7 @@
 	bfd_put_64 (output_bfd,
 		    sdyn->output_section->vma + sdyn->output_offset,
 		    sgot->contents);
-      /* Write GOT[1] and GOT[2], needed for the linker.  */
+      /* Write GOT[1] and GOT[2], needed for the dynamic linker.  */
       bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + GOT_ENTRY_SIZE);
       bfd_put_64 (output_bfd, (bfd_vma) 0, sgot->contents + GOT_ENTRY_SIZE*2);
     }

-- 
 Andreas Jaeger
  SuSE Labs aj@suse.de
   private aj@arthur.inka.de
    http://www.suse.de/~aj


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