This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[x86-64] Large model relocation
- From: Michael Matz <matz at suse dot de>
- To: binutils at sourceware dot org
- Cc: Jan Hubicka <jh at suse dot cz>, Daniel Jacobowitz <drow at false dot org>
- Date: Mon, 20 Mar 2006 18:45:48 +0100 (CET)
- Subject: [x86-64] Large model relocation
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