From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 21492 invoked by alias); 20 Mar 2006 17:46:05 -0000 Received: (qmail 21478 invoked by uid 22791); 20 Mar 2006 17:46:02 -0000 X-Spam-Check-By: sourceware.org Received: from ns1.suse.de (HELO mx1.suse.de) (195.135.220.2) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 20 Mar 2006 17:45:59 +0000 Received: from Relay1.suse.de (mail2.suse.de [195.135.221.8]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.suse.de (Postfix) with ESMTP id 2FEF1EF02; Mon, 20 Mar 2006 18:45:48 +0100 (CET) Date: Mon, 20 Mar 2006 18:36:00 -0000 From: Michael Matz To: binutils@sourceware.org Cc: Jan Hubicka , Daniel Jacobowitz Subject: [x86-64] Large model relocation Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-IsSubscribed: yes Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2006-03/txt/msg00277.txt.bz2 Hi, this patch adds the necessary support for the five new relocations for the large model. I've tested it on i386 and x86-64; it builds and doesn't cause breakage in the testsuite for both. Additionally we use this patch (or better a slightly adjusted version) since quite some time internally, so I know that it also builds several 1000 packages. Full large model support also would need a change in elf.sc moving the .plt after .text (so that .plt and .got have a chance to be nearer than 2GB). This is because I didn't bother to actually implement the new .plt layout which would be necessary for more than an abysmal number of exported symbols (102261124 to be exact). So the .plt code can't reach more than 2GB away, and as long as .text is between it and .got it can't be larger than the 2GB, which is the whole point of the large model. I'll post that as follow up after the heat about this one (should it rise up) colds down :-) Daniel: I would like to see this in 2.17 if possible, so that GCC could make use of it simply by version number. Ciao, Michael. bfd/ChangeLog: * reloc.c: Add BFD_RELOC_X86_64_GOT64, BFD_RELOC_X86_64_GOTPCREL64, BFD_RELOC_X86_64_GOTPC64, BFD_RELOC_X86_64_GOTPLT64, BFD_RELOC_X86_64_PLTOFF64. * bfd-in2.h: Regenerated. * libbfd.h: Regenerated. * elf64-x86-64.c (x86_64_elf_howto_table): Correct comment. Add howtos for above relocs. (x86_64_reloc_map): Add mappings for new relocs. (elf64_x86_64_check_relocs): R_X86_64_GOT64, R_X86_64_GOTPCREL64, R_X86_64_GOTPLT64 need a got entry. R_X86_64_GOTPLT64 also a PLT entry. R_X86_64_GOTPC64 needs a .got section. R_X86_64_PLTOFF64 needs a PLT entry. (elf64_x86_64_gc_sweep_hook): Reflect changes from elf64_x86_64_check_relocs for the new relocs. (elf64_x86_64_relocate_section): Handle new relocs. gas/ChangeLog: * config/tc-i386.c (type_names): Correct placement of 'static'. (reloc): Map some more relocs to their 64 bit counterpart when size is 8. (output_insn): Work around breakage if DEBUG386 is defined. (output_disp): A BFD_RELOC_64 with GOT_symbol as operand also needs to be mapped to BFD_RELOC_X86_64_GOTPC64 or BFD_RELOC_X86_64_GOTPC32. Also x86-64 handles pcrel addressing different from i386. (output_imm): Ditto. (lex_got): Recognize @PLTOFF and @GOTPLT. Make @GOT accept also Imm64. (md_convert_frag): Jumps can now be larger than 2GB away, error out in that case. (tc_gen_reloc): New relocs are passed through. BFD_RELOC_64 and BFD_RELOC_64_PCREL are mapped to BFD_RELOC_X86_64_GOTPC64. gas/testsuite/ChangeLog: * gas/i386/reloc64.s: Accept 64-bit forms. * gas/i386/reloc64.d: Adjust. * gas/i386/reloc64.l: Adjust. include/ChangeLog: * elf/x86-64.h: Add the new relocations with their official numbers. Index: bfd/bfd-in2.h =================================================================== RCS file: /cvs/src/src/bfd/bfd-in2.h,v retrieving revision 1.384 diff -u -p -r1.384 bfd-in2.h --- bfd/bfd-in2.h 16 Mar 2006 12:20:16 -0000 1.384 +++ bfd/bfd-in2.h 20 Mar 2006 17:04:03 -0000 @@ -2702,6 +2702,11 @@ in the instruction. */ BFD_RELOC_X86_64_TPOFF32, BFD_RELOC_X86_64_GOTOFF64, BFD_RELOC_X86_64_GOTPC32, + BFD_RELOC_X86_64_GOT64, + BFD_RELOC_X86_64_GOTPCREL64, + BFD_RELOC_X86_64_GOTPC64, + BFD_RELOC_X86_64_GOTPLT64, + BFD_RELOC_X86_64_PLTOFF64, BFD_RELOC_X86_64_GOTPC32_TLSDESC, BFD_RELOC_X86_64_TLSDESC_CALL, BFD_RELOC_X86_64_TLSDESC, Index: bfd/elf64-x86-64.c =================================================================== RCS file: /cvs/src/src/bfd/elf64-x86-64.c,v retrieving revision 1.112 diff -u -p -r1.112 elf64-x86-64.c --- bfd/elf64-x86-64.c 16 Mar 2006 12:20:15 -0000 1.112 +++ bfd/elf64-x86-64.c 20 Mar 2006 17:04:03 -0000 @@ -31,8 +31,8 @@ #define MINUS_ONE (~ (bfd_vma) 0) /* The relocation "howto" table. Order of fields: - type, size, bitsize, pc_relative, complain_on_overflow, - special_function, name, partial_inplace, src_mask, dst_pack, pcrel_offset. */ + type, rightshift, size, bitsize, pc_relative, bitpos, complain_on_overflow, + special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset. */ static reloc_howto_type x86_64_elf_howto_table[] = { HOWTO(R_X86_64_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont, @@ -112,11 +112,21 @@ static reloc_howto_type x86_64_elf_howto HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, bfd_elf_generic_reloc, "R_X86_64_GOTPC32", FALSE, 0xffffffff, 0xffffffff, TRUE), - EMPTY_HOWTO (27), - EMPTY_HOWTO (28), - EMPTY_HOWTO (29), - EMPTY_HOWTO (30), - EMPTY_HOWTO (31), + HOWTO(R_X86_64_GOT64, 0, 4, 64, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOT64", FALSE, MINUS_ONE, MINUS_ONE, + FALSE), + HOWTO(R_X86_64_GOTPCREL64, 0, 4, 64, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPCREL64", FALSE, MINUS_ONE, + MINUS_ONE, TRUE), + HOWTO(R_X86_64_GOTPC64, 0, 4, 64, TRUE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPC64", + FALSE, MINUS_ONE, MINUS_ONE, TRUE), + HOWTO(R_X86_64_GOTPLT64, 0, 4, 64, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_GOTPLT64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), + HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed, + bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE, + MINUS_ONE, FALSE), EMPTY_HOWTO (32), EMPTY_HOWTO (33), HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0, @@ -185,6 +195,11 @@ static const struct elf_reloc_map x86_64 { BFD_RELOC_64_PCREL, R_X86_64_PC64, }, { BFD_RELOC_X86_64_GOTOFF64, R_X86_64_GOTOFF64, }, { BFD_RELOC_X86_64_GOTPC32, R_X86_64_GOTPC32, }, + { BFD_RELOC_X86_64_GOT64, R_X86_64_GOT64, }, + { BFD_RELOC_X86_64_GOTPCREL64,R_X86_64_GOTPCREL64, }, + { BFD_RELOC_X86_64_GOTPC64, R_X86_64_GOTPC64, }, + { BFD_RELOC_X86_64_GOTPLT64, R_X86_64_GOTPLT64, }, + { BFD_RELOC_X86_64_PLTOFF64, R_X86_64_PLTOFF64, }, { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, }, { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, @@ -777,6 +792,9 @@ elf64_x86_64_check_relocs (bfd *abfd, st case R_X86_64_GOT32: case R_X86_64_GOTPCREL: case R_X86_64_TLSGD: + case R_X86_64_GOT64: + case R_X86_64_GOTPCREL64: + case R_X86_64_GOTPLT64: case R_X86_64_GOTPC32_TLSDESC: case R_X86_64_TLSDESC_CALL: /* This symbol requires a global offset table entry. */ @@ -795,6 +813,14 @@ elf64_x86_64_check_relocs (bfd *abfd, st if (h != NULL) { + if (r_type == R_X86_64_GOTPLT64) + { + /* This relocation indicates that we also need + a PLT entry, as this is a function. We don't need + a PLT entry for local symbols. */ + h->needs_plt = 1; + h->plt.refcount += 1; + } h->got.refcount += 1; old_tls_type = elf64_x86_64_hash_entry (h)->tls_type; } @@ -858,6 +884,7 @@ elf64_x86_64_check_relocs (bfd *abfd, st case R_X86_64_GOTOFF64: case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: create_got: if (htab->sgot == NULL) { @@ -885,6 +912,16 @@ elf64_x86_64_check_relocs (bfd *abfd, st h->plt.refcount += 1; break; + case R_X86_64_PLTOFF64: + /* This tries to form the 'address' of a function relative + to GOT. For global symbols we need a PLT entry. */ + if (h != NULL) + { + h->needs_plt = 1; + h->plt.refcount += 1; + } + goto create_got; + case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: @@ -1189,8 +1226,13 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, s case R_X86_64_GOTTPOFF: case R_X86_64_GOT32: case R_X86_64_GOTPCREL: + case R_X86_64_GOT64: + case R_X86_64_GOTPCREL64: + case R_X86_64_GOTPLT64: if (h != NULL) { + if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0) + h->plt.refcount -= 1; if (h->got.refcount > 0) h->got.refcount -= 1; } @@ -1215,6 +1257,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, s /* Fall thru */ case R_X86_64_PLT32: + case R_X86_64_PLTOFF64: if (h != NULL) { if (h->plt.refcount > 0) @@ -2096,11 +2139,23 @@ elf64_x86_64_relocate_section (bfd *outp copied into the output file to be resolved at run time. */ switch (r_type) { + asection *base_got; case R_X86_64_GOT32: + case R_X86_64_GOT64: /* Relocation is to the entry for this symbol in the global offset table. */ case R_X86_64_GOTPCREL: - /* Use global offset table as symbol value. */ + case R_X86_64_GOTPCREL64: + /* Use global offset table entry as symbol value. */ + case R_X86_64_GOTPLT64: + /* This is the same as GOT64 for relocation purposes, but + indicates the existence of a PLT entry. The difficulty is, + that we must calculate the GOT slot offset from the PLT + offset, if this symbol got a PLT entry (it was global). + Additionally if it's computed from the PLT entry, then that + GOT offset is relative to .got.plt, not to .got. */ + base_got = htab->sgot; + if (htab->sgot == NULL) abort (); @@ -2109,6 +2164,19 @@ elf64_x86_64_relocate_section (bfd *outp bfd_boolean dyn; off = h->got.offset; + if (h->needs_plt + && h->plt.offset != (bfd_vma)-1 + && off == (bfd_vma)-1) + { + /* We can't use h->got.offset here to save + state, or even just remember the offset, as + finish_dynamic_symbol would use that as offset into + .got. */ + bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; + off = (plt_index + 3) * GOT_ENTRY_SIZE; + base_got = htab->sgotplt; + } + dyn = htab->elf.dynamic_sections_created; if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) @@ -2133,7 +2201,9 @@ elf64_x86_64_relocate_section (bfd *outp else { bfd_put_64 (output_bfd, relocation, - htab->sgot->contents + off); + base_got->contents + off); + /* Note that this is harmless for the GOTPLT64 case, + as -1 | 1 still is -1. */ h->got.offset |= 1; } } @@ -2155,7 +2225,7 @@ elf64_x86_64_relocate_section (bfd *outp else { bfd_put_64 (output_bfd, relocation, - htab->sgot->contents + off); + base_got->contents + off); if (info->shared) { @@ -2169,8 +2239,8 @@ elf64_x86_64_relocate_section (bfd *outp if (s == NULL) abort (); - outrel.r_offset = (htab->sgot->output_section->vma - + htab->sgot->output_offset + outrel.r_offset = (base_got->output_section->vma + + base_got->output_offset + off); outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); outrel.r_addend = relocation; @@ -2186,9 +2256,9 @@ elf64_x86_64_relocate_section (bfd *outp if (off >= (bfd_vma) -2) abort (); - relocation = htab->sgot->output_section->vma - + htab->sgot->output_offset + off; - if (r_type != R_X86_64_GOTPCREL) + relocation = base_got->output_section->vma + + base_got->output_offset + off; + if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64) relocation -= htab->sgotplt->output_section->vma - htab->sgotplt->output_offset; @@ -2224,12 +2294,31 @@ elf64_x86_64_relocate_section (bfd *outp break; case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: /* Use global offset table as symbol value. */ relocation = htab->sgotplt->output_section->vma + htab->sgotplt->output_offset; unresolved_reloc = FALSE; break; + case R_X86_64_PLTOFF64: + /* Relocation is PLT entry relative to GOT. For local + symbols it's the symbol itself relative to GOT. */ + if (h != NULL + /* See PLT32 handling. */ + && h->plt.offset != (bfd_vma) -1 + && htab->splt != NULL) + { + relocation = (htab->splt->output_section->vma + + htab->splt->output_offset + + h->plt.offset); + unresolved_reloc = FALSE; + } + + relocation -= htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + break; + case R_X86_64_PLT32: /* Relocation is to the entry for this symbol in the procedure linkage table. */ Index: bfd/libbfd.h =================================================================== RCS file: /cvs/src/src/bfd/libbfd.h,v retrieving revision 1.175 diff -u -p -r1.175 libbfd.h --- bfd/libbfd.h 16 Mar 2006 12:20:16 -0000 1.175 +++ bfd/libbfd.h 20 Mar 2006 17:04:03 -0000 @@ -7,7 +7,7 @@ (This include file is not for users of the library.) Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, - 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Written by Cygnus Support. @@ -1062,6 +1062,11 @@ static const char *const bfd_reloc_code_ "BFD_RELOC_X86_64_TPOFF32", "BFD_RELOC_X86_64_GOTOFF64", "BFD_RELOC_X86_64_GOTPC32", + "BFD_RELOC_X86_64_GOT64", + "BFD_RELOC_X86_64_GOTPCREL64", + "BFD_RELOC_X86_64_GOTPC64", + "BFD_RELOC_X86_64_GOTPLT64", + "BFD_RELOC_X86_64_PLTOFF64", "BFD_RELOC_X86_64_GOTPC32_TLSDESC", "BFD_RELOC_X86_64_TLSDESC_CALL", "BFD_RELOC_X86_64_TLSDESC", Index: bfd/libcoff.h =================================================================== RCS file: /cvs/src/src/bfd/libcoff.h,v retrieving revision 1.43 diff -u -p -r1.43 libcoff.h --- bfd/libcoff.h 16 Mar 2006 12:20:16 -0000 1.43 +++ bfd/libcoff.h 20 Mar 2006 17:04:03 -0000 @@ -4,7 +4,7 @@ /* BFD COFF object file private structure. Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005 + 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. Written by Cygnus Support. Index: bfd/reloc.c =================================================================== RCS file: /cvs/src/src/bfd/reloc.c,v retrieving revision 1.149 diff -u -p -r1.149 reloc.c --- bfd/reloc.c 3 Mar 2006 15:25:29 -0000 1.149 +++ bfd/reloc.c 20 Mar 2006 17:04:03 -0000 @@ -2344,6 +2344,16 @@ ENUMX ENUMX BFD_RELOC_X86_64_GOTPC32 ENUMX + BFD_RELOC_X86_64_GOT64 +ENUMX + BFD_RELOC_X86_64_GOTPCREL64 +ENUMX + BFD_RELOC_X86_64_GOTPC64 +ENUMX + BFD_RELOC_X86_64_GOTPLT64 +ENUMX + BFD_RELOC_X86_64_PLTOFF64 +ENUMX BFD_RELOC_X86_64_GOTPC32_TLSDESC ENUMX BFD_RELOC_X86_64_TLSDESC_CALL Index: gas/config/tc-i386.c =================================================================== RCS file: /cvs/src/src/gas/config/tc-i386.c,v retrieving revision 1.207 diff -u -p -r1.207 tc-i386.c --- gas/config/tc-i386.c 27 Feb 2006 15:35:37 -0000 1.207 +++ gas/config/tc-i386.c 20 Mar 2006 17:04:03 -0000 @@ -1169,13 +1169,12 @@ ps (s) segment_name (S_GET_SEGMENT (s))); } -struct type_name +static struct type_name { unsigned int mask; char *tname; } - -static const type_names[] = +const type_names[] = { { Reg8, "r8" }, { Reg16, "r16" }, @@ -1238,6 +1237,18 @@ reloc (unsigned int size, if (size == 8) switch (other) { + case BFD_RELOC_X86_64_GOT32: + return BFD_RELOC_X86_64_GOT64; + break; + case BFD_RELOC_X86_64_PLTOFF64: + return BFD_RELOC_X86_64_PLTOFF64; + break; + case BFD_RELOC_X86_64_GOTPC32: + other = BFD_RELOC_X86_64_GOTPC64; + break; + case BFD_RELOC_X86_64_GOTPCREL: + other = BFD_RELOC_X86_64_GOTPCREL64; + break; case BFD_RELOC_X86_64_TPOFF32: other = BFD_RELOC_X86_64_TPOFF64; break; @@ -3569,7 +3580,7 @@ check_prefix: #ifdef DEBUG386 if (flag_debug) { - pi (line, &i); + pi ("" /*line*/, &i); } #endif /* DEBUG386 */ } @@ -3654,7 +3665,9 @@ output_disp (insn_start_frag, insn_start if (GOT_symbol && GOT_symbol == i.op[n].disps->X_add_symbol && (((reloc_type == BFD_RELOC_32 - || reloc_type == BFD_RELOC_X86_64_32S) + || reloc_type == BFD_RELOC_X86_64_32S + || (reloc_type == BFD_RELOC_64 + && object_64bit)) && (i.op[n].disps->X_op == O_symbol || (i.op[n].disps->X_op == O_add && ((symbol_get_value_expression @@ -3678,10 +3691,17 @@ output_disp (insn_start_frag, insn_start } if (!object_64bit) - reloc_type = BFD_RELOC_386_GOTPC; + { + reloc_type = BFD_RELOC_386_GOTPC; + i.op[n].imms->X_add_number += add; + } + else if (reloc_type == BFD_RELOC_64) + reloc_type = BFD_RELOC_X86_64_GOTPC64; else + /* Don't do the adjustment for x86-64, as there + the pcrel addressing is relative to the _next_ + insn, and that is taken care of in other code. */ reloc_type = BFD_RELOC_X86_64_GOTPC32; - i.op[n].disps->X_add_number += add; } fix_new_exp (frag_now, p - frag_now->fr_literal, size, i.op[n].disps, pcrel, reloc_type); @@ -3790,7 +3810,8 @@ output_imm (insn_start_frag, insn_start_ * confusing to do it this way. */ if ((reloc_type == BFD_RELOC_32 - || reloc_type == BFD_RELOC_X86_64_32S) + || reloc_type == BFD_RELOC_X86_64_32S + || reloc_type == BFD_RELOC_64) && GOT_symbol && GOT_symbol == i.op[n].imms->X_add_symbol && (i.op[n].imms->X_op == O_symbol @@ -3816,8 +3837,10 @@ output_imm (insn_start_frag, insn_start_ if (!object_64bit) reloc_type = BFD_RELOC_386_GOTPC; - else + else if (size == 4) reloc_type = BFD_RELOC_X86_64_GOTPC32; + else if (size == 8) + reloc_type = BFD_RELOC_X86_64_GOTPC64; i.op[n].imms->X_add_number += add; } fix_new_exp (frag_now, p - frag_now->fr_literal, size, @@ -3870,12 +3893,19 @@ lex_got (enum bfd_reloc_code_real *reloc int *adjust, unsigned int *types) { + /* Some of the relocations depend on the size of what field is to + be relocated. But in our callers i386_immediate and i386_displacement + we don't yet know the operand size (this will be set by insn + matching). Hence we record the word32 relocation here, + and adjust the reloc according to the real size in reloc(). */ static const struct { const char *str; const enum bfd_reloc_code_real rel[2]; const unsigned int types64; } gotrel[] = { + { "PLTOFF", { 0, BFD_RELOC_X86_64_PLTOFF64 }, Imm64 }, { "PLT", { BFD_RELOC_386_PLT32, BFD_RELOC_X86_64_PLT32 }, Imm32|Imm32S|Disp32 }, + { "GOTPLT", { 0, BFD_RELOC_X86_64_GOTPLT64 }, Imm64|Disp64 }, { "GOTOFF", { BFD_RELOC_386_GOTOFF, BFD_RELOC_X86_64_GOTOFF64 }, Imm64|Disp64 }, { "GOTPCREL", { 0, BFD_RELOC_X86_64_GOTPCREL }, Imm32|Imm32S|Disp32 }, { "TLSGD", { BFD_RELOC_386_TLS_GD, BFD_RELOC_X86_64_TLSGD }, Imm32|Imm32S|Disp32 }, @@ -3887,7 +3917,7 @@ lex_got (enum bfd_reloc_code_real *reloc { "DTPOFF", { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 }, { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE, 0 }, 0 }, { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE, 0 }, 0 }, - { "GOT", { BFD_RELOC_386_GOT32, BFD_RELOC_X86_64_GOT32 }, Imm32|Imm32S|Disp32 }, + { "GOT", { BFD_RELOC_386_GOT32, BFD_RELOC_X86_64_GOT32 }, Imm32|Imm32S|Disp32|Imm64 }, { "TLSDESC", { BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_X86_64_GOTPC32_TLSDESC }, Imm32|Imm32S|Disp32 }, { "TLSCALL", { BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_TLSDESC_CALL }, Imm32|Imm32S|Disp32 } }; @@ -4947,6 +4977,20 @@ md_convert_frag (abfd, sec, fragP) } } + /* If size if less then four we are sure that the operand fits, + but if it's 4, then it could be that the displacement is larger + then -/+ 2GB. */ + if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4 + && object_64bit + && ((addressT) (displacement_from_opcode_start - extension + + ((addressT) 1 << 31)) + > (((addressT) 2 << 31) - 1))) + { + as_bad_where (fragP->fr_file, fragP->fr_line, + _("jump target out of range")); + /* Make us emit 0. */ + displacement_from_opcode_start = extension; + } /* Now put displacement after opcode. */ md_number_to_chars ((char *) where_to_put_displacement, (valueT) (displacement_from_opcode_start - extension), @@ -5708,6 +5752,11 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_X86_64_TPOFF64: case BFD_RELOC_X86_64_GOTOFF64: case BFD_RELOC_X86_64_GOTPC32: + case BFD_RELOC_X86_64_GOT64: + case BFD_RELOC_X86_64_GOTPCREL64: + case BFD_RELOC_X86_64_GOTPC64: + case BFD_RELOC_X86_64_GOTPLT64: + case BFD_RELOC_X86_64_PLTOFF64: case BFD_RELOC_X86_64_GOTPC32_TLSDESC: case BFD_RELOC_X86_64_TLSDESC_CALL: case BFD_RELOC_RVA: @@ -5776,6 +5825,12 @@ tc_gen_reloc (section, fixp) else code = BFD_RELOC_X86_64_GOTPC32; } + if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL) + && GOT_symbol + && fixp->fx_addsy == GOT_symbol) + { + code = BFD_RELOC_X86_64_GOTPC64; + } rel = (arelent *) xmalloc (sizeof (arelent)); rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); Index: gas/testsuite/gas/i386/reloc64.d =================================================================== RCS file: /cvs/src/src/gas/testsuite/gas/i386/reloc64.d,v retrieving revision 1.2 diff -u -p -r1.2 reloc64.d --- gas/testsuite/gas/i386/reloc64.d 28 Sep 2005 14:44:25 -0000 1.2 +++ gas/testsuite/gas/i386/reloc64.d 20 Mar 2006 17:04:03 -0000 @@ -19,6 +19,7 @@ Disassembly of section \.text: .*[ ]+R_X86_64_PC32[ ]+xtrn\+0xf+c .*[ ]+R_X86_64_PC32[ ]+xtrn\+0xf+c .*[ ]+R_X86_64_PC8[ ]+xtrn\+0xf+f +.*[ ]+R_X86_64_GOT64[ ]+xtrn .*[ ]+R_X86_64_GOT32[ ]+xtrn .*[ ]+R_X86_64_GOT32[ ]+xtrn .*[ ]+R_X86_64_GOTOFF64[ ]+xtrn @@ -26,7 +27,7 @@ Disassembly of section \.text: .*[ ]+R_X86_64_GOTPCREL[ ]+xtrn .*[ ]+R_X86_64_GOTPCREL[ ]+xtrn\+0xf+c .*[ ]+R_X86_64_GOTPC32[ ]+_GLOBAL_OFFSET_TABLE_\+0x0*2 -.*[ ]+R_X86_64_GOTPC32[ ]+_GLOBAL_OFFSET_TABLE_\+0xf+f +.*[ ]+R_X86_64_GOTPC32[ ]+_GLOBAL_OFFSET_TABLE_\+0xf+c .*[ ]+R_X86_64_GOTPC32[ ]+_GLOBAL_OFFSET_TABLE_\+0x0*2 .*[ ]+R_X86_64_PLT32[ ]+xtrn .*[ ]+R_X86_64_PLT32[ ]+xtrn @@ -50,7 +51,9 @@ Disassembly of section \.data: #... .*[ ]+R_X86_64_64[ ]+xtrn .*[ ]+R_X86_64_PC64[ ]+xtrn +.*[ ]+R_X86_64_GOT64[ ]+xtrn .*[ ]+R_X86_64_GOTOFF64[ ]+xtrn +.*[ ]+R_X86_64_GOTPCREL64[ ]+xtrn .*[ ]+R_X86_64_DTPOFF64[ ]+xtrn .*[ ]+R_X86_64_TPOFF64[ ]+xtrn .*[ ]+R_X86_64_32[ ]+xtrn Index: gas/testsuite/gas/i386/reloc64.l =================================================================== RCS file: /cvs/src/src/gas/testsuite/gas/i386/reloc64.l,v retrieving revision 1.2 diff -u -p -r1.2 reloc64.l --- gas/testsuite/gas/i386/reloc64.l 28 Sep 2005 14:44:25 -0000 1.2 +++ gas/testsuite/gas/i386/reloc64.l 20 Mar 2006 17:04:03 -0000 @@ -1,6 +1,5 @@ .*: Assembler messages: .*:29: Error: .* -.*:33: Error: .* .*:35: Error: .* .*:36: Error: .* .*:37: Error: .* @@ -50,8 +49,6 @@ .*:123: Error: .* .*:125: Error: .* .*:126: Error: .* -.*:131: Error: .* -.*:133: Error: .* .*:136: Error: .* .*:137: Error: .* .*:138: Error: .* Index: gas/testsuite/gas/i386/reloc64.s =================================================================== RCS file: /cvs/src/src/gas/testsuite/gas/i386/reloc64.s,v retrieving revision 1.2 diff -u -p -r1.2 reloc64.s --- gas/testsuite/gas/i386/reloc64.s 28 Sep 2005 14:44:25 -0000 1.2 +++ gas/testsuite/gas/i386/reloc64.s 20 Mar 2006 17:04:03 -0000 @@ -30,7 +30,7 @@ bad mov xtrn(%eip), %eax call xtrn jrcxz xtrn -bad movabs $xtrn@got, %rax + movabs $xtrn@got, %rax add $xtrn@got, %rax bad mov $xtrn@got, %eax bad mov $xtrn@got, %ax @@ -128,9 +128,9 @@ bad call xtrn@tpoff .data .quad xtrn .quad xtrn - . -bad .quad xtrn@got + .quad xtrn@got .quad xtrn@gotoff -bad .quad xtrn@gotpcrel + .quad xtrn@gotpcrel ill .quad _GLOBAL_OFFSET_TABLE_ ill .quad _GLOBAL_OFFSET_TABLE_ - . bad .quad xtrn@plt Index: include/elf/x86-64.h =================================================================== RCS file: /cvs/src/src/include/elf/x86-64.h,v retrieving revision 1.9 diff -u -p -r1.9 x86-64.h --- include/elf/x86-64.h 18 Jan 2006 21:07:47 -0000 1.9 +++ include/elf/x86-64.h 20 Mar 2006 17:04:04 -0000 @@ -54,7 +54,16 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_ty RELOC_NUMBER (R_X86_64_GOTOFF64, 25) /* 64 bit offset to GOT */ RELOC_NUMBER (R_X86_64_GOTPC32, 26) /* 32 bit signed pc relative offset to GOT */ - /* 27 .. 33 */ + RELOC_NUMBER (R_X86_64_GOT64, 27) /* 64 bit GOT entry offset */ + RELOC_NUMBER (R_X86_64_GOTPCREL64, 28) /* 64 bit signed pc relative + offset to GOT entry */ + RELOC_NUMBER (R_X86_64_GOTPC64, 29) /* 64 bit signed pc relative + offset to GOT */ + RELOC_NUMBER (R_X86_64_GOTPLT64, 30) /* like GOT64, but indicates + that PLT entry is needed */ + RELOC_NUMBER (R_X86_64_PLTOFF64, 31) /* 64 bit GOT relative offset + to PLT entry */ + /* 32 .. 33 */ RELOC_NUMBER (R_X86_64_GOTPC32_TLSDESC, 34) /* 32 bit signed pc relative offset to TLS descriptor