summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Jaeger <aj@suse.de>2006-03-23 08:23:09 +0000
committerAndreas Jaeger <aj@suse.de>2006-03-23 08:23:09 +0000
commit0b2fec5a51a7128adac23ed728695de955476e7d (patch)
treed488cf8700f23aa448865f44ccf774bb6a1fb662
parent8eadf497bfaa1262341f838f93dec5dfeb08c659 (diff)
downloadbinutils-redhat-0b2fec5a51a7128adac23ed728695de955476e7d.tar.gz
Patch by matz@suse.de:
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.
-rw-r--r--bfd/bfd-in2.h5
-rw-r--r--bfd/elf64-x86-64.c119
-rw-r--r--bfd/libbfd.h7
-rw-r--r--bfd/libcoff.h2
-rw-r--r--bfd/reloc.c10
-rw-r--r--gas/config/tc-i386.c75
-rw-r--r--gas/testsuite/gas/i386/reloc64.d5
-rw-r--r--gas/testsuite/gas/i386/reloc64.l3
-rw-r--r--gas/testsuite/gas/i386/reloc64.s6
-rw-r--r--include/elf/x86-64.h11
10 files changed, 208 insertions, 35 deletions
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 62886c9284..20f4bbff9c 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2707,6 +2707,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,
diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 504a19b7b9..9befd69c5d 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -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_table[] =
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_reloc_map[] =
{ 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, struct bfd_link_info *info, asection *sec,
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, struct bfd_link_info *info, asection *sec,
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, struct bfd_link_info *info, asection *sec,
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, struct bfd_link_info *info, asection *sec,
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, struct bfd_link_info *info,
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, struct bfd_link_info *info,
/* 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 *output_bfd, struct bfd_link_info *info,
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 *output_bfd, struct bfd_link_info *info,
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 *output_bfd, struct bfd_link_info *info,
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 *output_bfd, struct bfd_link_info *info,
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 *output_bfd, struct bfd_link_info *info,
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 *output_bfd, struct bfd_link_info *info,
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 *output_bfd, struct bfd_link_info *info,
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. */
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 0c188688cd..94dfeb75a1 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -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.
@@ -1065,6 +1065,11 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"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",
diff --git a/bfd/libcoff.h b/bfd/libcoff.h
index b0b271c09a..f756f30b1b 100644
--- a/bfd/libcoff.h
+++ b/bfd/libcoff.h
@@ -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.
diff --git a/bfd/reloc.c b/bfd/reloc.c
index d0c3f30434..920a5f23bf 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2352,6 +2352,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
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index f42a9a4705..fe222da354 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -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_off)
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_off)
}
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_off)
* 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_off)
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 *));
diff --git a/gas/testsuite/gas/i386/reloc64.d b/gas/testsuite/gas/i386/reloc64.d
index 8503d23eea..11dfdb4fed 100644
--- a/gas/testsuite/gas/i386/reloc64.d
+++ b/gas/testsuite/gas/i386/reloc64.d
@@ -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
diff --git a/gas/testsuite/gas/i386/reloc64.l b/gas/testsuite/gas/i386/reloc64.l
index 62a762bc7e..87a5c772c3 100644
--- a/gas/testsuite/gas/i386/reloc64.l
+++ b/gas/testsuite/gas/i386/reloc64.l
@@ -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: .*
diff --git a/gas/testsuite/gas/i386/reloc64.s b/gas/testsuite/gas/i386/reloc64.s
index 1ae14ddcbe..47ebfa8dc0 100644
--- a/gas/testsuite/gas/i386/reloc64.s
+++ b/gas/testsuite/gas/i386/reloc64.s
@@ -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
diff --git a/include/elf/x86-64.h b/include/elf/x86-64.h
index 74655fbcd0..b09a558a35 100644
--- a/include/elf/x86-64.h
+++ b/include/elf/x86-64.h
@@ -54,7 +54,16 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_type)
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