This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Fix PLT for x86-64
- To: binutils at sources dot redhat dot com
- Subject: Fix PLT for x86-64
- From: Andreas Jaeger <aj at suse dot de>
- Date: 19 Apr 2001 10:02:25 +0200
- Cc: Bo Thorsen <bo at suse dot de>, Jan Hubicka <jh at suse dot cz>
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