diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2015-09-03 06:50:31 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2015-10-21 16:45:47 -0700 |
commit | 91d9e98ebf64688a62467541ab22cf2a7b4170f1 (patch) | |
tree | 0a5f5a3c866876dff80dfa4f88a25d7b9eab6d92 | |
parent | bed91f4da252b5f30d3cb4fd9f9febd61ad9560d (diff) | |
download | gdb-91d9e98ebf64688a62467541ab22cf2a7b4170f1.zip gdb-91d9e98ebf64688a62467541ab22cf2a7b4170f1.tar.gz gdb-91d9e98ebf64688a62467541ab22cf2a7b4170f1.tar.bz2 |
Add R_386_GOT32X support to gas and ld
This patch adds support for the R_386_GOT32X relocation proposed in
https://groups.google.com/forum/#!topic/ia32-abi/GbJJskkid4I
to gas and ld. It updates gas to generate R_386_GOT32X relocation for
memory operand, foo@GOT[(%reg)]. We must encode "mov foo@GOT, %eax"
with the 0x8b opcode, instead of the 0xb8 opcode, so that it can be
transformed to "lea foo, %eax". With the locally defined symbol, foo,
we convert
mov foo@GOT[(%reg1)], %reg2
to
lea foo[@GOTOFF(%reg1)], %reg2
and convert
call/jmp *foo@GOT[(%reg)]
to
nop call foo/jmp foo nop
When PIC is false, convert
test %reg1, foo@GOT[(%reg2)]
to
test $foo, %reg1
and convert
binop foo@GOT[(%reg1)], %reg2
to
binop $foo, %reg2
where binop is one of adc, add, and, cmp, or, sbb, sub, xor instructions.
bfd/
* elf32-i386.c: Include opcode/i386.h.
(elf_howto_table): Add R_386_GOT32X.
(R_386_ext2): Replace R_386_IRELATIVE with R_386_GOT32X.
(elf_i386_reloc_type_lookup): Handle BFD_RELOC_386_GOT32X.
(need_convert_mov_to_lea): Renamed to ...
(need_convert_load): This.
(elf_i386_check_relocs): Handle R_386_GOT32X. Replace
need_convert_mov_to_lea with need_convert_load.
(elf_i386_gc_sweep_hook): Handle R_386_GOT32X.
(elf_i386_size_dynamic_sections): Likewise.
(elf_i386_relocate_section): Likewise.
(elf_i386_convert_mov_to_lea): Renamed to ...
(elf_i386_convert_load): This. Replace need_convert_mov_to_lea
with need_convert_load. Support R_386_GOT32X transformations.
* reloc.c (BFD_RELOC_386_GOT32X): New.
* bfd-in2.h: Regenerated.
* libbfd.h: Likewise.
gas/
* config/tc-i386.c (tc_i386_fix_adjustable): Handle
BFD_RELOC_386_GOT32X.
(tc_gen_reloc): Likewise.
(match_template): Force 0x8b encoding for "mov foo@GOT, %eax".
(output_disp): Check for "call/jmp *mem", "mov mem, %reg",
"test %reg, mem" and "binop mem, %reg" where binop is one of
adc, add, and, cmp, or, sbb, sub, xor instructions. Set
fx_tcbit if the REX prefix is generated. Set fx_tcbit2 if
BFD_RELOC_386_GOT32X should be generated.
(i386_validate_fix): Generate BFD_RELOC_386_GOT32X if fx_tcbit2
is set.
gas/testsuite/
* gas/i386/got.d: New file.
* gas/i386/got.s: Likewise.
* gas/i386/i386.exp: Run got.
* gas/i386/localpic.d: Replace R_386_GOT32 with R_386_GOT32X.
* gas/i386/mixed-mode-reloc32.d: Likewise.
* gas/i386/reloc32.d: Likewise.
include/elf/
* i386.h (R_386_GOT32X): New relocation.
ld/testsuite/
* ld-i386/branch1.d: New file.
* ld-i386/branch1.s: Likewise.
* ld-i386/call1.d: Likewise.
* ld-i386/call1.s: Likewise.
* ld-i386/call2.d: Likewise.
* ld-i386/call2.s: Likewise.
* ld-i386/got1.dd: Likewise.
* ld-i386/got1.out: Likewise.
* ld-i386/got1a.S: Likewise.
* ld-i386/got1b.c: Likewise.
* ld-i386/got1c.c: Likewise.
* ld-i386/got1d.S: Likewise.
* ld-i386/jmp1.d: Likewise.
* ld-i386/jmp1.s: Likewise.
* ld-i386/jmp2.d: Likewise.
* ld-i386/jmp2.s: Likewise.
* ld-i386/load1.d: Likewise.
* ld-i386/load1.s: Likewise.
* ld-i386/load2.d: Likewise.
* ld-i386/load2.s: Likewise.
* ld-i386/load3.d: Likewise.
* ld-i386/load3.s: Likewise.
* ld-i386/load4.s: Likewise.
* ld-i386/load4a.d: Likewise.
* ld-i386/load4b.d: Likewise.
* ld-i386/load5.s: Likewise.
* ld-i386/load5a.d: Likewise.
* ld-i386/load5b.d: Likewise.
* ld-i386/load6.d: Likewise.
* ld-i386/load6.s: Likewise.
* ld-i386/i386.exp: Run branch1, call1, call2, jmp1, jmp2,
load1, load2, load3, load4a, load4b, load5a, load5b and load6
tests. Run got1 test.
47 files changed, 929 insertions, 69 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 60d7e45..ad246c8 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -3177,6 +3177,7 @@ instruction. */ BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_386_TLS_DESC, BFD_RELOC_386_IRELATIVE, + BFD_RELOC_386_GOT32X, /* x86-64/elf relocations */ BFD_RELOC_X86_64_GOT32, diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 8c1dadb..f56b39e 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -29,6 +29,7 @@ #include "objalloc.h" #include "hashtab.h" #include "dwarf2.h" +#include "opcode/i386.h" /* 386 uses REL relocations instead of RELA. */ #define USE_REL 1 @@ -146,9 +147,12 @@ static reloc_howto_type elf_howto_table[]= HOWTO(R_386_IRELATIVE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_IRELATIVE", TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_GOT32X, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GOT32X", + TRUE, 0xffffffff, 0xffffffff, FALSE), /* Another gap. */ -#define R_386_ext2 (R_386_IRELATIVE + 1 - R_386_tls_offset) +#define R_386_ext2 (R_386_GOT32X + 1 - R_386_tls_offset) #define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_ext2) /* GNU extension to record C++ vtable hierarchy. */ @@ -332,6 +336,10 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, TRACE ("BFD_RELOC_386_IRELATIVE"); return &elf_howto_table[R_386_IRELATIVE - R_386_tls_offset]; + case BFD_RELOC_386_GOT32X: + TRACE ("BFD_RELOC_386_GOT32X"); + return &elf_howto_table[R_386_GOT32X - R_386_tls_offset]; + case BFD_RELOC_VTABLE_INHERIT: TRACE ("BFD_RELOC_VTABLE_INHERIT"); return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset]; @@ -1468,7 +1476,7 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, /* Rename some of the generic section flags to better document how they are used here. */ -#define need_convert_mov_to_lea sec_flg0 +#define need_convert_load sec_flg0 /* Look through the relocs for a section during the first phase, and calculate needed space in the global offset table, procedure linkage @@ -1580,6 +1588,7 @@ elf_i386_check_relocs (bfd *abfd, case R_386_PC32: case R_386_PLT32: case R_386_GOT32: + case R_386_GOT32X: if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; if (!_bfd_elf_create_ifunc_sections (htab->elf.dynobj, info)) @@ -1637,6 +1646,7 @@ elf_i386_check_relocs (bfd *abfd, /* Fall through */ case R_386_GOT32: + case R_386_GOT32X: case R_386_TLS_GD: case R_386_TLS_GOTDESC: case R_386_TLS_DESC_CALL: @@ -1647,7 +1657,10 @@ elf_i386_check_relocs (bfd *abfd, switch (r_type) { default: - case R_386_GOT32: tls_type = GOT_NORMAL; break; + case R_386_GOT32: + case R_386_GOT32X: + tls_type = GOT_NORMAL; + break; case R_386_TLS_GD: tls_type = GOT_TLS_GD; break; case R_386_TLS_GOTDESC: case R_386_TLS_DESC_CALL: @@ -1948,9 +1961,9 @@ do_size: return FALSE; } - if (r_type == R_386_GOT32 + if ((r_type == R_386_GOT32 || r_type == R_386_GOT32X) && (h == NULL || h->type != STT_GNU_IFUNC)) - sec->need_convert_mov_to_lea = 1; + sec->need_convert_load = 1; } return TRUE; @@ -2074,6 +2087,7 @@ elf_i386_gc_sweep_hook (bfd *abfd, case R_386_TLS_IE: case R_386_TLS_GOTIE: case R_386_GOT32: + case R_386_GOT32X: if (h != NULL) { if (h->got.refcount > 0) @@ -2718,14 +2732,27 @@ elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) return TRUE; } -/* Convert - mov foo@GOT(%reg), %reg +/* With the local symbol, foo, we convert + mov foo@GOT[(%reg1)], %reg2 + to + lea foo[@GOTOFF(%reg1)], %reg2 + and convert + call/jmp *foo@GOT[(%reg)] to - lea foo@GOTOFF(%reg), %reg - with the local symbol, foo. */ + nop call foo/jmp foo nop + When PIC is false, convert + test %reg1, foo@GOT[(%reg2)] + to + test $foo, %reg1 + and convert + binop foo@GOT[(%reg1)], %reg2 + to + binop $foo, %reg2 + where binop is one of adc, add, and, cmp, or, sbb, sub, xor + instructions. */ static bfd_boolean -elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, +elf_i386_convert_load (bfd *abfd, asection *sec, struct bfd_link_info *link_info) { Elf_Internal_Shdr *symtab_hdr; @@ -2743,7 +2770,7 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, /* Nothing to do if there is no need or no output. */ if ((sec->flags & (SEC_CODE | SEC_RELOC)) != (SEC_CODE | SEC_RELOC) - || sec->need_convert_mov_to_lea == 0 + || sec->need_convert_load == 0 || bfd_is_abs_section (sec->output_section)) return TRUE; @@ -2777,32 +2804,92 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, unsigned int r_symndx = ELF32_R_SYM (irel->r_info); unsigned int indx; struct elf_link_hash_entry *h; + unsigned int opcode; + unsigned int modrm; + bfd_vma roff; + bfd_boolean baseless; + Elf_Internal_Sym *isym; + unsigned int addend; + unsigned int nop; + bfd_vma nop_offset; - if (r_type != R_386_GOT32) + if (r_type != R_386_GOT32 && r_type != R_386_GOT32X) continue; - /* Get the symbol referred to by the reloc. */ - if (r_symndx < symtab_hdr->sh_info) + roff = irel->r_offset; + if (roff < 2) + continue; + + modrm = bfd_get_8 (abfd, contents + roff - 1); + baseless = (modrm & 0xc7) == 0x5; + + if (r_type == R_386_GOT32X + && baseless + && bfd_link_pic (link_info)) { - Elf_Internal_Sym *isym; + /* For PIC, disallow R_386_GOT32X without a base register + since we don't know what the GOT base is. Allow + R_386_GOT32 for existing object files. */ + const char *name; + + if (r_symndx < symtab_hdr->sh_info) + { + isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, + r_symndx); + name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL); + } + else + { + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (abfd)[indx]; + BFD_ASSERT (h != NULL); + name = h->root.root.string; + } + + (*_bfd_error_handler) + (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base register can not be used when making a shared object"), + abfd, name); + goto error_return; + } + + opcode = bfd_get_8 (abfd, contents + roff - 2); + + /* It is OK to convert mov to lea. */ + if (opcode != 0x8b) + { + /* Only convert R_386_GOT32X relocation for call, jmp or + one of adc, add, and, cmp, or, sbb, sub, test, xor + instructions. */ + if (r_type != R_386_GOT32X) + continue; + + /* It is OK to convert indirect branch to direct branch. It + is OK to convert adc, add, and, cmp, or, sbb, sub, test, + xor only when PIC is false. */ + if (opcode != 0xff && bfd_link_pic (link_info)) + continue; + } + /* Try to convert R_386_GOT32 and R_386_GOT32X. Get the symbol + referred to by the reloc. */ + if (r_symndx < symtab_hdr->sh_info) + { isym = bfd_sym_from_r_symndx (&htab->sym_cache, abfd, r_symndx); - /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. */ - if (ELF_ST_TYPE (isym->st_info) != STT_GNU_IFUNC - && irel->r_offset >= 2 - && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b) - { - bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2); - irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); - if (local_got_refcounts != NULL - && local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; - changed_contents = TRUE; - changed_relocs = TRUE; - } - continue; + /* STT_GNU_IFUNC must keep GOT32 relocations. */ + if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) + continue; + + h = NULL; + if (opcode == 0x0ff) + /* Convert "call/jmp *foo@GOT[(%reg)]". */ + goto convert_branch; + else + /* Convert "mov foo@GOT[(%reg1)], %reg2", + "test %reg1, foo@GOT(%reg2)" and + "binop foo@GOT[(%reg1)], %reg2". */ + goto convert_load; } indx = r_symndx - symtab_hdr->sh_info; @@ -2813,22 +2900,147 @@ elf_i386_convert_mov_to_lea (bfd *abfd, asection *sec, || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; - /* STT_GNU_IFUNC must keep R_386_GOT32 relocation. We also avoid - optimizing _DYNAMIC since ld.so may use its link-time address. */ - if ((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->type != STT_GNU_IFUNC - && h != htab->elf.hdynamic - && SYMBOL_REFERENCES_LOCAL (link_info, h) - && irel->r_offset >= 2 - && bfd_get_8 (abfd, contents + irel->r_offset - 2) == 0x8b) + /* STT_GNU_IFUNC must keep GOT32 relocations. */ + if (h->type == STT_GNU_IFUNC) + continue; + + if (opcode == 0xff) + { + /* We have "call/jmp *foo@GOT[(%reg)]". */ + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && SYMBOL_REFERENCES_LOCAL (link_info, h)) + { + /* The function is locally defined. */ +convert_branch: + addend = bfd_get_32 (abfd, contents + roff); + /* Addend for R_386_GOT32X relocation must be 0. */ + if (addend != 0) + continue; + + /* Convert R_386_GOT32X to R_386_PC32. */ + if (modrm == 0x15 || (modrm & 0xf8) == 0x90) + { + /* Convert to "nop call foo". ADDR_PREFIX_OPCODE + is a nop prefix. */ + modrm = 0xe8; + nop = ADDR_PREFIX_OPCODE; + nop_offset = roff - 2; + } + else + { + /* Convert to "jmp foo nop". */ + modrm = 0xe9; + nop = NOP_OPCODE; + nop_offset = roff + 3; + irel->r_offset -= 1; + } + + bfd_put_8 (abfd, nop, contents + nop_offset); + bfd_put_8 (abfd, modrm, contents + irel->r_offset - 1); + /* When converting to PC-relative relocation, we + need to adjust addend by -4. */ + bfd_put_32 (abfd, -4, contents + irel->r_offset); + irel->r_info = ELF32_R_INFO (r_symndx, R_386_PC32); + + if (h) + { + if (h->got.refcount > 0) + h->got.refcount -= 1; + } + else + { + if (local_got_refcounts != NULL + && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + } + + changed_contents = TRUE; + changed_relocs = TRUE; + } + } + else { - bfd_put_8 (abfd, 0x8d, contents + irel->r_offset - 2); - irel->r_info = ELF32_R_INFO (r_symndx, R_386_GOTOFF); - if (h->got.refcount > 0) - h->got.refcount -= 1; - changed_contents = TRUE; - changed_relocs = TRUE; + /* We have "mov foo@GOT[(%re1g)], %reg2", + "test %reg1, foo@GOT(%reg2)" and + "binop foo@GOT[(%reg1)], %reg2". + + Avoid optimizing _DYNAMIC since ld.so may use its + link-time address. */ + if (h == htab->elf.hdynamic) + continue; + + if ((h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && SYMBOL_REFERENCES_LOCAL (link_info, h)) + { +convert_load: + if (opcode == 0x8b) + { + /* Convert "mov foo@GOT(%reg1), %reg2" to + "lea foo@GOTOFF(%reg1), %reg2". */ + if (r_type == R_386_GOT32X + && (baseless || !bfd_link_pic (link_info))) + { + r_type = R_386_32; + /* For R_386_32, convert + "lea foo@GOTOFF(%reg1), %reg2" to + "lea foo@GOT, %reg2". */ + if (!baseless) + { + modrm = 0x5 | (modrm & 0x38); + bfd_put_8 (abfd, modrm, contents + roff - 1); + } + } + else + r_type = R_386_GOTOFF; + opcode = 0x8d; + } + else + { + /* Addend for R_386_GOT32X relocation must be 0. */ + addend = bfd_get_32 (abfd, contents + roff); + if (addend != 0) + continue; + + if (opcode == 0x85) + { + /* Convert "test %reg1, foo@GOT(%reg2)" to + "test $foo, %reg1". */ + modrm = 0xc0 | (modrm & 0x38) >> 3; + opcode = 0xf7; + } + else + { + /* Convert "binop foo@GOT(%reg1), %reg2" to + "binop $foo, %reg2". */ + modrm = (0xc0 + | (modrm & 0x38) >> 3 + | (opcode & 0x3c)); + opcode = 0x81; + } + bfd_put_8 (abfd, modrm, contents + roff - 1); + r_type = R_386_32; + } + + bfd_put_8 (abfd, opcode, contents + roff - 2); + irel->r_info = ELF32_R_INFO (r_symndx, r_type); + + if (h) + { + if (h->got.refcount > 0) + h->got.refcount -= 1; + } + else + { + if (local_got_refcounts != NULL + && local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + } + + changed_contents = TRUE; + changed_relocs = TRUE; + } } } @@ -2914,7 +3126,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { struct elf_dyn_relocs *p; - if (!elf_i386_convert_mov_to_lea (ibfd, s, info)) + if (!elf_i386_convert_load (ibfd, s, info)) return FALSE; for (p = ((struct elf_dyn_relocs *) @@ -3664,6 +3876,7 @@ elf_i386_relocate_section (bfd *output_bfd, goto do_relocation; case R_386_GOT32: + case R_386_GOT32X: base_got = htab->elf.sgot; off = h->got.offset; @@ -3741,7 +3954,61 @@ elf_i386_relocate_section (bfd *output_bfd, eh = (struct elf_i386_link_hash_entry *) h; switch (r_type) { + case R_386_GOT32X: + /* Avoid optimizing _DYNAMIC since ld.so may use its + link-time address. */ + if (h == htab->elf.hdynamic) + goto r_386_got32; + + if (bfd_link_pic (info)) + { + /* It is OK to convert mov to lea and convert indirect + branch to direct branch. It is OK to convert adc, + add, and, cmp, or, sbb, sub, test, xor only when PIC + is false. */ + unsigned int opcode; + opcode = bfd_get_8 (abfd, contents + rel->r_offset - 2); + if (opcode != 0x8b && opcode != 0xff) + goto r_386_got32; + } + + /* Resolve "mov GOT[(%reg)], %reg", + "call/jmp *GOT[(%reg)]", "test %reg, foo@GOT[(%reg)]" + and "binop foo@GOT[(%reg)], %reg". */ + if (h == NULL + || (h->plt.offset == (bfd_vma) -1 + && h->got.offset == (bfd_vma) -1) + || htab->elf.sgotplt == NULL) + abort (); + + offplt = (htab->elf.sgotplt->output_section->vma + + htab->elf.sgotplt->output_offset); + + /* It is relative to .got.plt section. */ + if (h->got.offset != (bfd_vma) -1) + /* Use GOT entry. */ + relocation = (htab->elf.sgot->output_section->vma + + htab->elf.sgot->output_offset + + h->got.offset - offplt); + else + /* Use GOTPLT entry. */ + relocation = (h->plt.offset / plt_entry_size - 1 + 3) * 4; + + if (!bfd_link_pic (info)) + { + /* If not PIC, add the .got.plt section address for + baseless adressing. */ + unsigned int modrm; + modrm = bfd_get_8 (abfd, contents + rel->r_offset - 1); + if ((modrm & 0xc7) == 0x5) + relocation += offplt; + } + + unresolved_reloc = FALSE; + break; + case R_386_GOT32: +r_386_got32: /* Relocation is to the entry for this symbol in the global offset table. */ if (htab->elf.sgot == NULL) diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 9ae9ba2..3bf1400 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1292,6 +1292,7 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_386_TLS_DESC_CALL", "BFD_RELOC_386_TLS_DESC", "BFD_RELOC_386_IRELATIVE", + "BFD_RELOC_386_GOT32X", "BFD_RELOC_X86_64_GOT32", "BFD_RELOC_X86_64_PLT32", "BFD_RELOC_X86_64_COPY", diff --git a/bfd/reloc.c b/bfd/reloc.c index 886c63e..c6e2807 100644 --- a/bfd/reloc.c +++ b/bfd/reloc.c @@ -2676,6 +2676,8 @@ ENUMX BFD_RELOC_386_TLS_DESC ENUMX BFD_RELOC_386_IRELATIVE +ENUMX + BFD_RELOC_386_GOT32X ENUMDOC i386/elf relocations diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index b5c27ee..dd1a41b 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -2928,6 +2928,7 @@ tc_i386_fix_adjustable (fixS *fixP ATTRIBUTE_UNUSED) || fixP->fx_r_type == BFD_RELOC_386_GOTOFF || fixP->fx_r_type == BFD_RELOC_386_PLT32 || fixP->fx_r_type == BFD_RELOC_386_GOT32 + || fixP->fx_r_type == BFD_RELOC_386_GOT32X || fixP->fx_r_type == BFD_RELOC_386_TLS_GD || fixP->fx_r_type == BFD_RELOC_386_TLS_LDM || fixP->fx_r_type == BFD_RELOC_386_TLS_LDO_32 @@ -4791,6 +4792,10 @@ match_template (void) } } + /* Force 0x8b encoding for "mov foo@GOT, %eax". */ + if (i.reloc[0] == BFD_RELOC_386_GOT32 && t->base_opcode == 0xa0) + continue; + /* We check register size if needed. */ check_register = t->opcode_modifier.checkregsize; overlap0 = operand_type_and (i.types[0], operand_types[0]); @@ -7157,6 +7162,7 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) int size = disp_size (n); int sign = i.types[n].bitfield.disp32s; int pcrel = (i.flags[n] & Operand_PCrel) != 0; + fixS *fixP; /* We can't have 8 bit displacement here. */ gas_assert (!i.types[n].bitfield.disp8); @@ -7225,8 +7231,34 @@ output_disp (fragS *insn_start_frag, offsetT insn_start_off) insn, and that is taken care of in other code. */ reloc_type = BFD_RELOC_X86_64_GOTPC32; } - fix_new_exp (frag_now, p - frag_now->fr_literal, size, - i.op[n].disps, pcrel, reloc_type); + fixP = fix_new_exp (frag_now, p - frag_now->fr_literal, + size, i.op[n].disps, pcrel, + reloc_type); + /* Check for "call/jmp *mem", "mov mem, %reg", + "test %reg, mem" and "binop mem, %reg" where binop + is one of adc, add, and, cmp, or, sbb, sub, xor + instructions. */ + if ((i.rm.mode == 2 + || (i.rm.mode == 0 && i.rm.regmem == 5)) + && ((i.operands == 1 + && i.tm.base_opcode == 0xff + && (i.rm.reg == 2 || i.rm.reg == 4)) + || (i.operands == 2 + && (i.tm.base_opcode == 0x8b + || i.tm.base_opcode == 0x85 + || (i.tm.base_opcode & 0xc7) == 0x03)))) + { + if (object_64bit) + { + fixP->fx_tcbit = i.rex != 0; + if (i.base_reg + && (i.base_reg->reg_num == RegRip + || i.base_reg->reg_num == RegEip)) + fixP->fx_tcbit2 = 1; + } + else + fixP->fx_tcbit2 = 1; + } } } } @@ -10321,23 +10353,39 @@ s_bss (int ignore ATTRIBUTE_UNUSED) void i386_validate_fix (fixS *fixp) { - if (fixp->fx_subsy && fixp->fx_subsy == GOT_symbol) + if (fixp->fx_subsy) { - if (fixp->fx_r_type == BFD_RELOC_32_PCREL) - { - if (!object_64bit) - abort (); - fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; - } - else + if (fixp->fx_subsy == GOT_symbol) { - if (!object_64bit) - fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + if (fixp->fx_r_type == BFD_RELOC_32_PCREL) + { + if (!object_64bit) + abort (); +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + if (fixp->fx_tcbit2) + fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; + else +#endif + fixp->fx_r_type = BFD_RELOC_X86_64_GOTPCREL; + } else - fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; + { + if (!object_64bit) + fixp->fx_r_type = BFD_RELOC_386_GOTOFF; + else + fixp->fx_r_type = BFD_RELOC_X86_64_GOTOFF64; + } + fixp->fx_subsy = 0; } - fixp->fx_subsy = 0; } +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) + else if (!object_64bit) + { + if (fixp->fx_r_type == BFD_RELOC_386_GOT32 + && fixp->fx_tcbit2) + fixp->fx_r_type = BFD_RELOC_386_GOT32X; + } +#endif } arelent * @@ -10373,6 +10421,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) case BFD_RELOC_X86_64_GOTPCREL: case BFD_RELOC_386_PLT32: case BFD_RELOC_386_GOT32: + case BFD_RELOC_386_GOT32X: case BFD_RELOC_386_GOTOFF: case BFD_RELOC_386_GOTPC: case BFD_RELOC_386_TLS_GD: diff --git a/gas/testsuite/gas/i386/got.d b/gas/testsuite/gas/i386/got.d new file mode 100644 index 0000000..f76ca47 --- /dev/null +++ b/gas/testsuite/gas/i386/got.d @@ -0,0 +1,29 @@ +#objdump: -dwr + +.*: +file format .* + + +Disassembly of section .text: + +0+ <_start>: +[ ]*[a-f0-9]+: b8 00 00 00 00 mov \$0x0,%eax 1: R_386_GOT32 foo +[ ]*[a-f0-9]+: 8b 05 00 00 00 00 mov 0x0,%eax 7: R_386_GOT32X foo +[ ]*[a-f0-9]+: 8b 80 00 00 00 00 mov 0x0\(%eax\),%eax d: R_386_GOT32X foo +[ ]*[a-f0-9]+: 05 00 00 00 00 add \$0x0,%eax 12: R_386_GOT32 foo +[ ]*[a-f0-9]+: 03 05 00 00 00 00 add 0x0,%eax 18: R_386_GOT32X foo +[ ]*[a-f0-9]+: 03 80 00 00 00 00 add 0x0\(%eax\),%eax 1e: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff 15 00 00 00 00 call \*0x0 24: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff 90 00 00 00 00 call \*0x0\(%eax\) 2a: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff 25 00 00 00 00 jmp \*0x0 30: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff a0 00 00 00 00 jmp \*0x0\(%eax\) 36: R_386_GOT32X foo +[ ]*[a-f0-9]+: b8 00 00 00 00 mov \$0x0,%eax 3b: R_386_GOT32 foo +[ ]*[a-f0-9]+: 8b 05 00 00 00 00 mov 0x0,%eax 41: R_386_GOT32X foo +[ ]*[a-f0-9]+: 8b 80 00 00 00 00 mov 0x0\(%eax\),%eax 47: R_386_GOT32X foo +[ ]*[a-f0-9]+: 05 00 00 00 00 add \$0x0,%eax 4c: R_386_GOT32 foo +[ ]*[a-f0-9]+: 03 05 00 00 00 00 add 0x0,%eax 52: R_386_GOT32X foo +[ ]*[a-f0-9]+: 03 80 00 00 00 00 add 0x0\(%eax\),%eax 58: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff 90 00 00 00 00 call \*0x0\(%eax\) 5e: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff 15 00 00 00 00 call \*0x0 64: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff a0 00 00 00 00 jmp \*0x0\(%eax\) 6a: R_386_GOT32X foo +[ ]*[a-f0-9]+: ff 25 00 00 00 00 jmp \*0x0 70: R_386_GOT32X foo +#pass diff --git a/gas/testsuite/gas/i386/got.s b/gas/testsuite/gas/i386/got.s new file mode 100644 index 0000000..10fa881 --- /dev/null +++ b/gas/testsuite/gas/i386/got.s @@ -0,0 +1,29 @@ + .text +_start: + movl $foo@GOT, %eax + movl foo@GOT, %eax + movl foo@GOT(%eax), %eax + + addl $foo@GOT, %eax + addl foo@GOT, %eax + addl foo@GOT(%eax), %eax + + call *foo@GOT + call *foo@GOT(%eax) + jmp *foo@GOT + jmp *foo@GOT(%eax) + + .intel_syntax noprefix + + mov eax, offset foo@got + mov eax, DWORD PTR [foo@GOT] + mov eax, DWORD PTR [eax + foo@GOT] + + add eax, offset foo@got + add eax, DWORD PTR [foo@GOT] + add eax, DWORD PTR [eax + foo@GOT] + + call DWORD PTR [eax + foo@GOT] + call DWORD PTR [foo@GOT] + jmp DWORD PTR [eax + foo@GOT] + jmp DWORD PTR [foo@GOT] diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index f59b598..8c374f2 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -404,6 +404,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_32_check]] run_dump_test "relax-3" run_dump_test "relax-4" + run_dump_test "got" + if {![istarget "*-*-nacl*"]} then { run_dump_test "iamcu-1" run_dump_test "iamcu-2" diff --git a/gas/testsuite/gas/i386/localpic.d b/gas/testsuite/gas/i386/localpic.d index 93ac871..04fb5ce 100644 --- a/gas/testsuite/gas/i386/localpic.d +++ b/gas/testsuite/gas/i386/localpic.d @@ -3,7 +3,7 @@ Relocation section '.rel.text' at offset 0x[0-9a-f]+ contains 1 entries: Offset Info Type Sym.Value Sym. Name -[0-9a-f]+ +[0-9a-f]+ R_386_GOT32 +[0-9a-f]+ +foo +[0-9a-f]+ +[0-9a-f]+ R_386_GOT32X +[0-9a-f]+ +foo #... +[0-9]+: +[0-9a-f]+ +[0-9a-f]+ +NOTYPE +LOCAL +DEFAULT +[0-9]+ +foo #pass diff --git a/gas/testsuite/gas/i386/mixed-mode-reloc32.d b/gas/testsuite/gas/i386/mixed-mode-reloc32.d index 6bc52f7..9affc36 100644 --- a/gas/testsuite/gas/i386/mixed-mode-reloc32.d +++ b/gas/testsuite/gas/i386/mixed-mode-reloc32.d @@ -6,9 +6,9 @@ RELOCATION RECORDS FOR \[.text\]: OFFSET[ ]+TYPE[ ]+VALUE[ ]* -[0-9a-f]+[ ]+R_386_GOT32[ ]+xtrn[ ]* +[0-9a-f]+[ ]+R_386_GOT32X[ ]+xtrn[ ]* [0-9a-f]+[ ]+R_386_PLT32[ ]+xtrn[ ]* -[0-9a-f]+[ ]+R_386_GOT32[ ]+xtrn[ ]* +[0-9a-f]+[ ]+R_386_GOT32X[ ]+xtrn[ ]* [0-9a-f]+[ ]+R_386_PLT32[ ]+xtrn[ ]* -[0-9a-f]+[ ]+R_386_GOT32[ ]+xtrn[ ]* +[0-9a-f]+[ ]+R_386_GOT32X[ ]+xtrn[ ]* [0-9a-f]+[ ]+R_386_PLT32[ ]+xtrn[ ]* diff --git a/gas/testsuite/gas/i386/reloc32.d b/gas/testsuite/gas/i386/reloc32.d index cbd71d6..45c9cd2 100644 --- a/gas/testsuite/gas/i386/reloc32.d +++ b/gas/testsuite/gas/i386/reloc32.d @@ -18,7 +18,7 @@ Disassembly of section \.text: .*[ ]+R_386_PC32[ ]+xtrn .*[ ]+R_386_PC8[ ]+xtrn .*[ ]+R_386_GOT32[ ]+xtrn -.*[ ]+R_386_GOT32[ ]+xtrn +.*[ ]+R_386_GOT32X[ ]+xtrn .*[ ]+R_386_GOTOFF[ ]+xtrn .*[ ]+R_386_GOTOFF[ ]+xtrn .*[ ]+R_386_GOTPC[ ]+_GLOBAL_OFFSET_TABLE_ diff --git a/include/elf/i386.h b/include/elf/i386.h index 08c9455..dea65f4 100644 --- a/include/elf/i386.h +++ b/include/elf/i386.h @@ -66,6 +66,8 @@ START_RELOC_NUMBERS (elf_i386_reloc_type) RELOC_NUMBER (R_386_TLS_DESC_CALL,40) RELOC_NUMBER (R_386_TLS_DESC, 41) RELOC_NUMBER (R_386_IRELATIVE, 42) /* Adjust indirectly by program base */ + /* Load from 32 bit GOT entry, relaxable. */ + RELOC_NUMBER (R_386_GOT32X, 43) /* Used by Intel. */ RELOC_NUMBER (R_386_USED_BY_INTEL_200, 200) diff --git a/ld/testsuite/ld-i386/branch1.d b/ld/testsuite/ld-i386/branch1.d new file mode 100644 index 0000000..a078f1d --- /dev/null +++ b/ld/testsuite/ld-i386/branch1.d @@ -0,0 +1,17 @@ +#as: --32 +#ld: -melf_i386 +#objdump: -dw + +.*: +file format .* + + +Disassembly of section .text: + +#... +[ ]*[a-f0-9]+: 67 e8 ([0-9a-f]{2} ){4} * addr16 call +[a-f0-9]+ <foo> +[ ]*[a-f0-9]+: 67 e8 ([0-9a-f]{2} ){4} * addr16 call +[a-f0-9]+ <bar> +[ ]*[a-f0-9]+: e9 ([0-9a-f]{2} ){4} * jmp +[a-f0-9]+ <foo> +[ ]*[a-f0-9]+: 90 nop +[ ]*[a-f0-9]+: e9 ([0-9a-f]{2} ){4} * jmp +[a-f0-9]+ <bar> +[ ]*[a-f0-9]+: 90 nop +#pass diff --git a/ld/testsuite/ld-i386/branch1.s b/ld/testsuite/ld-i386/branch1.s new file mode 100644 index 0000000..0ccf5cf --- /dev/null +++ b/ld/testsuite/ld-i386/branch1.s @@ -0,0 +1,15 @@ + .text + .type bar, @function +bar: + ret + .globl foo + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + call *foo@GOT + call *bar@GOT + jmp *foo@GOT + jmp *bar@GOT diff --git a/ld/testsuite/ld-i386/call1.d b/ld/testsuite/ld-i386/call1.d new file mode 100644 index 0000000..69383b2 --- /dev/null +++ b/ld/testsuite/ld-i386/call1.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -shared -melf_i386 +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/call1.s b/ld/testsuite/ld-i386/call1.s new file mode 100644 index 0000000..ce003c8 --- /dev/null +++ b/ld/testsuite/ld-i386/call1.s @@ -0,0 +1,9 @@ + .text + .globl foo + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + call *foo@GOT diff --git a/ld/testsuite/ld-i386/call2.d b/ld/testsuite/ld-i386/call2.d new file mode 100644 index 0000000..69383b2 --- /dev/null +++ b/ld/testsuite/ld-i386/call2.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -shared -melf_i386 +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/call2.s b/ld/testsuite/ld-i386/call2.s new file mode 100644 index 0000000..57cd88f --- /dev/null +++ b/ld/testsuite/ld-i386/call2.s @@ -0,0 +1,8 @@ + .text + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + call *foo@GOT diff --git a/ld/testsuite/ld-i386/got1.dd b/ld/testsuite/ld-i386/got1.dd new file mode 100644 index 0000000..e46153d --- /dev/null +++ b/ld/testsuite/ld-i386/got1.dd @@ -0,0 +1,20 @@ +#... +[a-f0-9]+ <main>: +[ ]*[a-f0-9]+: 83 ec 0c sub \$0xc,%esp +[ ]*[a-f0-9]+: [ a-f0-9]+ addr16 call [a-f0-9]+ <foo> +[ ]*[a-f0-9]+: [ a-f0-9]+ call \*0x[a-f0-9]+ +[ ]*[a-f0-9]+: [ a-f0-9]+ call \*0x[a-f0-9]+ +[ ]*[a-f0-9]+: [ a-f0-9]+ lea *0x[a-f0-9]+,%eax +[ ]*[a-f0-9]+: ff d0 call \*%eax +[ ]*[a-f0-9]+: [ a-f0-9]+ mov *0x[a-f0-9]+,%eax +[ ]*[a-f0-9]+: ff d0 call \*%eax +[ ]*[a-f0-9]+: [ a-f0-9]+ mov *0x[a-f0-9]+,%eax +[ ]*[a-f0-9]+: ff d0 call \*%eax +[ ]*[a-f0-9]+: [ a-f0-9]+ lea *0x[a-f0-9]+,%ecx +[ ]*[a-f0-9]+: ff d1 call \*%ecx +[ ]*[a-f0-9]+: 83 ec 0c sub \$0xc,%esp +[ ]*[a-f0-9]+: 6a 00 push \$0x0 +[ ]*[a-f0-9]+: 6a 00 push \$0x0 +[ ]*[a-f0-9]+: [ a-f0-9]+ jmp [a-f0-9]+ <myexit> +[ ]*[a-f0-9]+: 90 nop +#pass diff --git a/ld/testsuite/ld-i386/got1.out b/ld/testsuite/ld-i386/got1.out new file mode 100644 index 0000000..99d4f7f --- /dev/null +++ b/ld/testsuite/ld-i386/got1.out @@ -0,0 +1,7 @@ +foo +bar +plt +foo +bar +plt +foo diff --git a/ld/testsuite/ld-i386/got1a.S b/ld/testsuite/ld-i386/got1a.S new file mode 100644 index 0000000..f3d5330 --- /dev/null +++ b/ld/testsuite/ld-i386/got1a.S @@ -0,0 +1,21 @@ + .text + .globl main + .type main, @function +main: + subl $12, %esp + call *foo@GOT + call *bar@GOT + call *plt@GOT + movl foo@GOT, %eax + call *%eax + movl bar@GOT, %eax + call *%eax + movl plt@GOT, %eax + call *%eax + movl foo@GOT(%ebx), %ecx + call *%ecx + subl $12, %esp + pushl $0 + pushl $0 # Push a dummy return address onto stack. + jmp *myexit@GOT + .size main, .-main diff --git a/ld/testsuite/ld-i386/got1b.c b/ld/testsuite/ld-i386/got1b.c new file mode 100644 index 0000000..cf0c78e --- /dev/null +++ b/ld/testsuite/ld-i386/got1b.c @@ -0,0 +1,7 @@ +#include <stdio.h> + +void +foo (void) +{ + printf ("%s\n", __FUNCTION__); +} diff --git a/ld/testsuite/ld-i386/got1c.c b/ld/testsuite/ld-i386/got1c.c new file mode 100644 index 0000000..05f5fc2 --- /dev/null +++ b/ld/testsuite/ld-i386/got1c.c @@ -0,0 +1,7 @@ +#include <stdlib.h> + +void +myexit (int status) +{ + exit (status); +} diff --git a/ld/testsuite/ld-i386/got1d.S b/ld/testsuite/ld-i386/got1d.S new file mode 100644 index 0000000..a6d51c6 --- /dev/null +++ b/ld/testsuite/ld-i386/got1d.S @@ -0,0 +1,54 @@ + .globl bar + .type bar, @function +bar: + pushl %ebx + call __x86.get_pc_thunk.cx + addl $_GLOBAL_OFFSET_TABLE_, %ecx + subl $24, %esp + leal __FUNCTION__.1862@GOTOFF(%ecx), %eax + movl %eax, (%esp) + call *puts@GOT(%ecx) + addl $24, %esp + popl %ebx + ret + .size bar, .-bar + + .globl plt + .type plt, @function +plt: + pushl %esi + pushl %ebx + call __x86.get_pc_thunk.bx +1: + addl $_GLOBAL_OFFSET_TABLE_, %ebx + subl $20, %esp + leal __FUNCTION__.1866@GOTOFF(%ebx), %esi + movl %esi, (%esp) + call *puts@GOT(%ebx) + addl $20, %esp + popl %ebx + popl %esi + ret + .section .rodata + .type __FUNCTION__.1866, @object + .size __FUNCTION__.1866, 4 +__FUNCTION__.1866: + .string "plt" + .type __FUNCTION__.1862, @object + .size __FUNCTION__.1862, 4 +__FUNCTION__.1862: + .string "bar" + .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat + .globl __x86.get_pc_thunk.bx + .hidden __x86.get_pc_thunk.bx + .type __x86.get_pc_thunk.bx, @function +__x86.get_pc_thunk.bx: + movl (%esp), %ebx + ret + .section .text.__x86.get_pc_thunk.cx,"axG",@progbits,__x86.get_pc_thunk.cx,comdat + .globl __x86.get_pc_thunk.cx + .hidden __x86.get_pc_thunk.cx + .type __x86.get_pc_thunk.cx, @function +__x86.get_pc_thunk.cx: + movl (%esp), %ecx + ret diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index 8cddfce..3d28dcc 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -293,6 +293,19 @@ run_dump_test "lea1e" run_dump_test "lea1f" run_dump_test "mov1a" run_dump_test "mov1b" +run_dump_test "branch1" +run_dump_test "call1" +run_dump_test "call2" +run_dump_test "jmp1" +run_dump_test "jmp2" +run_dump_test "load1" +run_dump_test "load2" +run_dump_test "load3" +run_dump_test "load4a" +run_dump_test "load4b" +run_dump_test "load5a" +run_dump_test "load5b" +run_dump_test "load6" if { !([istarget "i?86-*-linux*"] || [istarget "i?86-*-gnu*"] @@ -498,6 +511,22 @@ if { [isnative] "" \ "pr19031.so" \ ] \ + [list \ + "Build got1d.so" \ + "-shared" \ + "" \ + { got1d.S } \ + "" \ + "got1d.so" \ + ] \ + [list \ + "Build gotpc1" \ + "tmpdir/got1d.so" \ + "" \ + { got1a.S got1b.c got1c.c } \ + {{objdump {-dw} got1.dd}} \ + "got1" \ + ] \ ] run_ld_link_exec_tests [] [list \ @@ -568,6 +597,14 @@ if { [isnative] "pr19031" \ "pr19031.out" \ ] \ + [list \ + "Run got1" \ + "tmpdir/got1d.so" \ + "" \ + { got1a.S got1b.c got1c.c } \ + "got1" \ + "got1.out" \ + ] \ ] } diff --git a/ld/testsuite/ld-i386/jmp1.d b/ld/testsuite/ld-i386/jmp1.d new file mode 100644 index 0000000..69383b2 --- /dev/null +++ b/ld/testsuite/ld-i386/jmp1.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -shared -melf_i386 +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/jmp1.s b/ld/testsuite/ld-i386/jmp1.s new file mode 100644 index 0000000..8c80696 --- /dev/null +++ b/ld/testsuite/ld-i386/jmp1.s @@ -0,0 +1,9 @@ + .text + .globl foo + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + jmp *foo@GOT diff --git a/ld/testsuite/ld-i386/jmp2.d b/ld/testsuite/ld-i386/jmp2.d new file mode 100644 index 0000000..69383b2 --- /dev/null +++ b/ld/testsuite/ld-i386/jmp2.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -shared -melf_i386 +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/jmp2.s b/ld/testsuite/ld-i386/jmp2.s new file mode 100644 index 0000000..b4bc38d --- /dev/null +++ b/ld/testsuite/ld-i386/jmp2.s @@ -0,0 +1,8 @@ + .text + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + jmp *foo@GOT diff --git a/ld/testsuite/ld-i386/lea1c.d b/ld/testsuite/ld-i386/lea1c.d index c84f413..54ec0de 100644 --- a/ld/testsuite/ld-i386/lea1c.d +++ b/ld/testsuite/ld-i386/lea1c.d @@ -9,6 +9,6 @@ Disassembly of section .text: #... -[ ]*[a-f0-9]+: 8d 81 ([0-9a-f]{2} ){4} * lea -0x[a-f0-9]+\(%ecx\),%eax -[ ]*[a-f0-9]+: 8d 81 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+\(%ecx\),%eax +[ ]*[a-f0-9]+: 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+,%eax +[ ]*[a-f0-9]+: 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+,%eax #pass diff --git a/ld/testsuite/ld-i386/load1.d b/ld/testsuite/ld-i386/load1.d new file mode 100644 index 0000000..e93531e --- /dev/null +++ b/ld/testsuite/ld-i386/load1.d @@ -0,0 +1,57 @@ +#as: --32 +#ld: -melf_i386 +#objdump: -dw --sym + +.*: +file format .* + +SYMBOL TABLE: +#... +0+8049170 l O .data 0+1 bar +#... +0+8049171 g O .data 0+1 foo +#... + +Disassembly of section .text: + +0+8048074 <_start>: +[ ]*[a-f0-9]+: 8d 05 70 91 04 08 lea 0x8049170,%eax +[ ]*[a-f0-9]+: 81 d0 70 91 04 08 adc \$0x8049170,%eax +[ ]*[a-f0-9]+: 81 c3 70 91 04 08 add \$0x8049170,%ebx +[ ]*[a-f0-9]+: 81 e1 70 91 04 08 and \$0x8049170,%ecx +[ ]*[a-f0-9]+: 81 fa 70 91 04 08 cmp \$0x8049170,%edx +[ ]*[a-f0-9]+: 81 cf 70 91 04 08 or \$0x8049170,%edi +[ ]*[a-f0-9]+: 81 de 70 91 04 08 sbb \$0x8049170,%esi +[ ]*[a-f0-9]+: 81 ed 70 91 04 08 sub \$0x8049170,%ebp +[ ]*[a-f0-9]+: 81 f4 70 91 04 08 xor \$0x8049170,%esp +[ ]*[a-f0-9]+: f7 c1 70 91 04 08 test \$0x8049170,%ecx +[ ]*[a-f0-9]+: 8d 05 70 91 04 08 lea 0x8049170,%eax +[ ]*[a-f0-9]+: 81 d0 70 91 04 08 adc \$0x8049170,%eax +[ ]*[a-f0-9]+: 81 c3 70 91 04 08 add \$0x8049170,%ebx +[ ]*[a-f0-9]+: 81 e1 70 91 04 08 and \$0x8049170,%ecx +[ ]*[a-f0-9]+: 81 fa 70 91 04 08 cmp \$0x8049170,%edx +[ ]*[a-f0-9]+: 81 cf 70 91 04 08 or \$0x8049170,%edi +[ ]*[a-f0-9]+: 81 de 70 91 04 08 sbb \$0x8049170,%esi +[ ]*[a-f0-9]+: 81 ed 70 91 04 08 sub \$0x8049170,%ebp +[ ]*[a-f0-9]+: 81 f4 70 91 04 08 xor \$0x8049170,%esp +[ ]*[a-f0-9]+: f7 c1 70 91 04 08 test \$0x8049170,%ecx +[ ]*[a-f0-9]+: 8d 05 71 91 04 08 lea 0x8049171,%eax +[ ]*[a-f0-9]+: 81 d0 71 91 04 08 adc \$0x8049171,%eax +[ ]*[a-f0-9]+: 81 c3 71 91 04 08 add \$0x8049171,%ebx +[ ]*[a-f0-9]+: 81 e1 71 91 04 08 and \$0x8049171,%ecx +[ ]*[a-f0-9]+: 81 fa 71 91 04 08 cmp \$0x8049171,%edx +[ ]*[a-f0-9]+: 81 cf 71 91 04 08 or \$0x8049171,%edi +[ ]*[a-f0-9]+: 81 de 71 91 04 08 sbb \$0x8049171,%esi +[ ]*[a-f0-9]+: 81 ed 71 91 04 08 sub \$0x8049171,%ebp +[ ]*[a-f0-9]+: 81 f4 71 91 04 08 xor \$0x8049171,%esp +[ ]*[a-f0-9]+: f7 c1 71 91 04 08 test \$0x8049171,%ecx +[ ]*[a-f0-9]+: 8d 05 71 91 04 08 lea 0x8049171,%eax +[ ]*[a-f0-9]+: 81 d0 71 91 04 08 adc \$0x8049171,%eax +[ ]*[a-f0-9]+: 81 c3 71 91 04 08 add \$0x8049171,%ebx +[ ]*[a-f0-9]+: 81 e1 71 91 04 08 and \$0x8049171,%ecx +[ ]*[a-f0-9]+: 81 fa 71 91 04 08 cmp \$0x8049171,%edx +[ ]*[a-f0-9]+: 81 cf 71 91 04 08 or \$0x8049171,%edi +[ ]*[a-f0-9]+: 81 de 71 91 04 08 sbb \$0x8049171,%esi +[ ]*[a-f0-9]+: 81 ed 71 91 04 08 sub \$0x8049171,%ebp +[ ]*[a-f0-9]+: 81 f4 71 91 04 08 xor \$0x8049171,%esp +[ ]*[a-f0-9]+: f7 c1 71 91 04 08 test \$0x8049171,%ecx +#pass diff --git a/ld/testsuite/ld-i386/load1.s b/ld/testsuite/ld-i386/load1.s new file mode 100644 index 0000000..a9f8460 --- /dev/null +++ b/ld/testsuite/ld-i386/load1.s @@ -0,0 +1,55 @@ + .data + .type bar, @object +bar: + .byte 1 + .size bar, .-bar + .globl foo + .type foo, @object +foo: + .byte 1 + .size foo, .-foo + .text + .globl _start + .type _start, @function +_start: + movl bar@GOT(%ecx), %eax + adcl bar@GOT(%ecx), %eax + addl bar@GOT(%ecx), %ebx + andl bar@GOT(%ecx), %ecx + cmpl bar@GOT(%ecx), %edx + orl bar@GOT(%ecx), %edi + sbbl bar@GOT(%ecx), %esi + subl bar@GOT(%ecx), %ebp + xorl bar@GOT(%ecx), %esp + testl %ecx, bar@GOT(%ecx) + movl bar@GOT, %eax + adcl bar@GOT, %eax + addl bar@GOT, %ebx + andl bar@GOT, %ecx + cmpl bar@GOT, %edx + orl bar@GOT, %edi + sbbl bar@GOT, %esi + subl bar@GOT, %ebp + xorl bar@GOT, %esp + testl %ecx, bar@GOT + movl foo@GOT(%ecx), %eax + adcl foo@GOT(%ecx), %eax + addl foo@GOT(%ecx), %ebx + andl foo@GOT(%ecx), %ecx + cmpl foo@GOT(%ecx), %edx + orl foo@GOT(%ecx), %edi + sbbl foo@GOT(%ecx), %esi + subl foo@GOT(%ecx), %ebp + xorl foo@GOT(%ecx), %esp + testl %ecx, foo@GOT(%ecx) + movl foo@GOT, %eax + adcl foo@GOT, %eax + addl foo@GOT, %ebx + andl foo@GOT, %ecx + cmpl foo@GOT, %edx + orl foo@GOT, %edi + sbbl foo@GOT, %esi + subl foo@GOT, %ebp + xorl foo@GOT, %esp + testl %ecx, foo@GOT + .size _start, .-_start diff --git a/ld/testsuite/ld-i386/load2.d b/ld/testsuite/ld-i386/load2.d new file mode 100644 index 0000000..87c2509 --- /dev/null +++ b/ld/testsuite/ld-i386/load2.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -melf_i386 -shared +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/load2.s b/ld/testsuite/ld-i386/load2.s new file mode 100644 index 0000000..7aad5d0 --- /dev/null +++ b/ld/testsuite/ld-i386/load2.s @@ -0,0 +1,8 @@ + .data + .type foo, @object +foo: + .text + .globl _start + .type _start, @function +_start: + addl foo@GOT, %ebx diff --git a/ld/testsuite/ld-i386/load3.d b/ld/testsuite/ld-i386/load3.d new file mode 100644 index 0000000..87c2509 --- /dev/null +++ b/ld/testsuite/ld-i386/load3.d @@ -0,0 +1,3 @@ +#as: --32 +#ld: -melf_i386 -shared +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/load3.s b/ld/testsuite/ld-i386/load3.s new file mode 100644 index 0000000..d9b7083 --- /dev/null +++ b/ld/testsuite/ld-i386/load3.s @@ -0,0 +1,9 @@ + .data + .globl foo + .type foo, @object +foo: + .text + .globl _start + .type _start, @function +_start: + addl foo@GOT, %ebx diff --git a/ld/testsuite/ld-i386/load4.s b/ld/testsuite/ld-i386/load4.s new file mode 100644 index 0000000..fe2c4cd --- /dev/null +++ b/ld/testsuite/ld-i386/load4.s @@ -0,0 +1,9 @@ + .text + .globl foo + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + movl foo@GOT, %eax diff --git a/ld/testsuite/ld-i386/load4a.d b/ld/testsuite/ld-i386/load4a.d new file mode 100644 index 0000000..3aa56bd --- /dev/null +++ b/ld/testsuite/ld-i386/load4a.d @@ -0,0 +1,4 @@ +#source: load4.s +#as: --32 +#ld: -Bsymbolic -shared -melf_i386 +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/load4b.d b/ld/testsuite/ld-i386/load4b.d new file mode 100644 index 0000000..0f6f4e2 --- /dev/null +++ b/ld/testsuite/ld-i386/load4b.d @@ -0,0 +1,13 @@ +#source: load4.s +#as: --32 +#ld: -melf_i386 +#objdump: -dw + +.*: +file format .* + + +Disassembly of section .text: + +#... +[ ]*[a-f0-9]+: 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+,%eax +#pass diff --git a/ld/testsuite/ld-i386/load5.s b/ld/testsuite/ld-i386/load5.s new file mode 100644 index 0000000..1ecd50c --- /dev/null +++ b/ld/testsuite/ld-i386/load5.s @@ -0,0 +1,8 @@ + .text + .type foo, @function +foo: + ret + .globl _start + .type _start, @function +_start: + movl foo@GOT, %eax diff --git a/ld/testsuite/ld-i386/load5a.d b/ld/testsuite/ld-i386/load5a.d new file mode 100644 index 0000000..88c225a --- /dev/null +++ b/ld/testsuite/ld-i386/load5a.d @@ -0,0 +1,4 @@ +#source: load5.s +#as: --32 +#ld: -Bsymbolic -shared -melf_i386 +#error: direct GOT relocation R_386_GOT32X against `foo' without base register can not be used when making a shared object diff --git a/ld/testsuite/ld-i386/load5b.d b/ld/testsuite/ld-i386/load5b.d new file mode 100644 index 0000000..6db0b28 --- /dev/null +++ b/ld/testsuite/ld-i386/load5b.d @@ -0,0 +1,13 @@ +#source: load5.s +#as: --32 +#ld: -melf_i386 +#objdump: -dw + +.*: +file format .* + + +Disassembly of section .text: + +#... +[ ]*[a-f0-9]+: 8d 05 ([0-9a-f]{2} ){4} * lea 0x[a-f0-9]+,%eax +#pass diff --git a/ld/testsuite/ld-i386/load6.d b/ld/testsuite/ld-i386/load6.d new file mode 100644 index 0000000..69319cf --- /dev/null +++ b/ld/testsuite/ld-i386/load6.d @@ -0,0 +1,28 @@ +#as: --32 +#ld: -shared -melf_i386 +#objdump: -dw + +.*: +file format .* + +Disassembly of section .text: + +[a-f0-9]+ <_start>: +[ ]*[a-f0-9]+: 13 81 f8 ff ff ff adc -0x8\(%ecx\),%eax +[ ]*[a-f0-9]+: 03 99 f8 ff ff ff add -0x8\(%ecx\),%ebx +[ ]*[a-f0-9]+: 23 89 f8 ff ff ff and -0x8\(%ecx\),%ecx +[ ]*[a-f0-9]+: 3b 91 f8 ff ff ff cmp -0x8\(%ecx\),%edx +[ ]*[a-f0-9]+: 0b b9 f8 ff ff ff or -0x8\(%ecx\),%edi +[ ]*[a-f0-9]+: 1b b1 f8 ff ff ff sbb -0x8\(%ecx\),%esi +[ ]*[a-f0-9]+: 2b a9 f8 ff ff ff sub -0x8\(%ecx\),%ebp +[ ]*[a-f0-9]+: 33 a1 f8 ff ff ff xor -0x8\(%ecx\),%esp +[ ]*[a-f0-9]+: 85 89 f8 ff ff ff test %ecx,-0x8\(%ecx\) +[ ]*[a-f0-9]+: 13 81 fc ff ff ff adc -0x4\(%ecx\),%eax +[ ]*[a-f0-9]+: 03 99 fc ff ff ff add -0x4\(%ecx\),%ebx +[ ]*[a-f0-9]+: 23 89 fc ff ff ff and -0x4\(%ecx\),%ecx +[ ]*[a-f0-9]+: 3b 91 fc ff ff ff cmp -0x4\(%ecx\),%edx +[ ]*[a-f0-9]+: 0b b9 fc ff ff ff or -0x4\(%ecx\),%edi +[ ]*[a-f0-9]+: 1b b1 fc ff ff ff sbb -0x4\(%ecx\),%esi +[ ]*[a-f0-9]+: 2b a9 fc ff ff ff sub -0x4\(%ecx\),%ebp +[ ]*[a-f0-9]+: 33 a1 fc ff ff ff xor -0x4\(%ecx\),%esp +[ ]*[a-f0-9]+: 85 89 fc ff ff ff test %ecx,-0x4\(%ecx\) +#pass diff --git a/ld/testsuite/ld-i386/load6.s b/ld/testsuite/ld-i386/load6.s new file mode 100644 index 0000000..eac3137 --- /dev/null +++ b/ld/testsuite/ld-i386/load6.s @@ -0,0 +1,33 @@ + .data + .type bar, @object +bar: + .byte 1 + .size bar, .-bar + .globl foo + .type foo, @object +foo: + .byte 1 + .size foo, .-foo + .text + .globl _start + .type _start, @function +_start: + adcl bar@GOT(%ecx), %eax + addl bar@GOT(%ecx), %ebx + andl bar@GOT(%ecx), %ecx + cmpl bar@GOT(%ecx), %edx + orl bar@GOT(%ecx), %edi + sbbl bar@GOT(%ecx), %esi + subl bar@GOT(%ecx), %ebp + xorl bar@GOT(%ecx), %esp + testl %ecx, bar@GOT(%ecx) + adcl foo@GOT(%ecx), %eax + addl foo@GOT(%ecx), %ebx + andl foo@GOT(%ecx), %ecx + cmpl foo@GOT(%ecx), %edx + orl foo@GOT(%ecx), %edi + sbbl foo@GOT(%ecx), %esi + subl foo@GOT(%ecx), %ebp + xorl foo@GOT(%ecx), %esp + testl %ecx, foo@GOT(%ecx) + .size _start, .-_start diff --git a/ld/testsuite/ld-i386/plt-main1.rd b/ld/testsuite/ld-i386/plt-main1.rd index d27589e..53c49d9 100644 --- a/ld/testsuite/ld-i386/plt-main1.rd +++ b/ld/testsuite/ld-i386/plt-main1.rd @@ -1,3 +1,3 @@ #... -[0-9a-f ]+R_386_GOT32 +0+ +bar +[0-9a-f ]+R_386_GOT32X +0+ +bar #pass diff --git a/ld/testsuite/ld-i386/plt-main3.rd b/ld/testsuite/ld-i386/plt-main3.rd index 7b78818..417fb20 100644 --- a/ld/testsuite/ld-i386/plt-main3.rd +++ b/ld/testsuite/ld-i386/plt-main3.rd @@ -1,5 +1,5 @@ #... -[0-9a-f ]+R_386_GOT32 +0+ +bar +[0-9a-f ]+R_386_GOT32X +0+ +bar #... [0-9a-f ]+R_386_PLT32 +0+ +bar #pass diff --git a/ld/testsuite/ld-i386/plt-main4.rd b/ld/testsuite/ld-i386/plt-main4.rd index 882a3ad..393fe29 100644 --- a/ld/testsuite/ld-i386/plt-main4.rd +++ b/ld/testsuite/ld-i386/plt-main4.rd @@ -1,5 +1,5 @@ #... -[0-9a-f ]+R_386_GOT32 +0+ +foo +[0-9a-f ]+R_386_GOT32X +0+ +foo #... [0-9a-f ]+R_386_PLT32 +0+ +foo #pass |