* config/tc-s390.c (s390_tls_suffix): New function.

(elf_suffix_type): Add suffix enums for TLS relocations.
	(s390_elf_suffix): Add suffix strings for TLS relocations.
	(s390_elf_cons): Map new lenght/elf suffix combinations for TLS to
	bfd relocations.
	(md_gather_operands): Map new instruction operand/elf suffix
	combinations for TLS to bfd relocations.
	(tc_s390_fix_adjustable): Add new TLS relocations.
	(tc_s390_force_relocation): Likewise.
	(md_apply_fix3): Likewise.
This commit is contained in:
Martin Schwidefsky
2003-01-24 17:14:25 +00:00
parent 69fc87f180
commit 1971b29d35
2 changed files with 231 additions and 30 deletions

View File

@@ -1,3 +1,16 @@
2003-01-24 Martin Schwidefsky <schwidefsky@de.ibm.com>
* config/tc-s390.c (s390_tls_suffix): New function.
(elf_suffix_type): Add suffix enums for TLS relocations.
(s390_elf_suffix): Add suffix strings for TLS relocations.
(s390_elf_cons): Map new lenght/elf suffix combinations for TLS to
bfd relocations.
(md_gather_operands): Map new instruction operand/elf suffix
combinations for TLS to bfd relocations.
(tc_s390_fix_adjustable): Add new TLS relocations.
(tc_s390_force_relocation): Likewise.
(md_apply_fix3): Likewise.
2003-01-24 Alan Modra <amodra@bigpond.net.au> 2003-01-24 Alan Modra <amodra@bigpond.net.au>
* as.h: Update copyright date. * as.h: Update copyright date.

View File

@@ -600,6 +600,67 @@ s390_insert_operand (insn, operand, val, file, line)
} }
} }
struct map_tls
{
char *string;
int length;
bfd_reloc_code_real_type reloc;
};
static bfd_reloc_code_real_type s390_tls_suffix
PARAMS ((char **, expressionS *));
/* Parse tls marker and return the desired relocation. */
static bfd_reloc_code_real_type
s390_tls_suffix (str_p, exp_p)
char **str_p;
expressionS *exp_p;
{
static struct map_tls mapping[] =
{
{ "tls_load", 8, BFD_RELOC_390_TLS_LOAD },
{ "tls_gdcall", 10, BFD_RELOC_390_TLS_GDCALL },
{ "tls_ldcall", 10, BFD_RELOC_390_TLS_LDCALL },
{ NULL, 0, BFD_RELOC_UNUSED }
};
struct map_tls *ptr;
char *orig_line;
char *str;
char *ident;
int len;
str = *str_p;
if (*str++ != ':')
return BFD_RELOC_UNUSED;
ident = str;
while (ISIDNUM (*str))
str++;
len = str - ident;
if (*str++ != ':')
return BFD_RELOC_UNUSED;
orig_line = input_line_pointer;
input_line_pointer = str;
expression (exp_p);
str = input_line_pointer;
if (&input_line_pointer != str_p)
input_line_pointer = orig_line;
if (exp_p->X_op != O_symbol)
return BFD_RELOC_UNUSED;
for (ptr = &mapping[0]; ptr->length > 0; ptr++)
if (len == ptr->length
&& strncasecmp (ident, ptr->string, ptr->length) == 0)
{
/* Found a matching tls suffix. */
*str_p = str;
return ptr->reloc;
}
return BFD_RELOC_UNUSED;
}
/* Structure used to hold suffixes. */ /* Structure used to hold suffixes. */
typedef enum typedef enum
{ {
@@ -609,7 +670,13 @@ typedef enum
ELF_SUFFIX_GOTENT, ELF_SUFFIX_GOTENT,
ELF_SUFFIX_GOTOFF, ELF_SUFFIX_GOTOFF,
ELF_SUFFIX_GOTPLT, ELF_SUFFIX_GOTPLT,
ELF_SUFFIX_PLTOFF ELF_SUFFIX_PLTOFF,
ELF_SUFFIX_TLS_GD,
ELF_SUFFIX_TLS_GOTIE,
ELF_SUFFIX_TLS_IE,
ELF_SUFFIX_TLS_LDM,
ELF_SUFFIX_TLS_LDO,
ELF_SUFFIX_TLS_LE
} }
elf_suffix_type; elf_suffix_type;
@@ -641,6 +708,12 @@ s390_elf_suffix (str_p, exp_p)
{ "gotoff", 6, ELF_SUFFIX_GOTOFF }, { "gotoff", 6, ELF_SUFFIX_GOTOFF },
{ "gotplt", 6, ELF_SUFFIX_GOTPLT }, { "gotplt", 6, ELF_SUFFIX_GOTPLT },
{ "pltoff", 6, ELF_SUFFIX_PLTOFF }, { "pltoff", 6, ELF_SUFFIX_PLTOFF },
{ "tlsgd", 5, ELF_SUFFIX_TLS_GD },
{ "gotntpoff", 9, ELF_SUFFIX_TLS_GOTIE },
{ "indntpoff", 9, ELF_SUFFIX_TLS_IE },
{ "tlsldm", 6, ELF_SUFFIX_TLS_LDM },
{ "dtpoff", 6, ELF_SUFFIX_TLS_LDO },
{ "ntpoff", 6, ELF_SUFFIX_TLS_LE },
{ NULL, 0, ELF_SUFFIX_NONE } { NULL, 0, ELF_SUFFIX_NONE }
}; };
@@ -956,38 +1029,72 @@ s390_elf_cons (nbytes)
int size; int size;
char *where; char *where;
if (nbytes == 2 && suffix == ELF_SUFFIX_GOT) if (nbytes == 2)
reloc = BFD_RELOC_390_GOT16; {
else if (nbytes == 4 && suffix == ELF_SUFFIX_GOT) static bfd_reloc_code_real_type tab2[] =
reloc = BFD_RELOC_32_GOT_PCREL; {
else if (nbytes == 8 && suffix == ELF_SUFFIX_GOT) [ELF_SUFFIX_NONE] BFD_RELOC_UNUSED ,
reloc = BFD_RELOC_390_GOT64; [ELF_SUFFIX_GOT] BFD_RELOC_390_GOT16,
else if (nbytes == 2 && suffix == ELF_SUFFIX_GOTOFF) [ELF_SUFFIX_PLT] BFD_RELOC_UNUSED,
reloc = BFD_RELOC_16_GOTOFF; [ELF_SUFFIX_GOTENT] BFD_RELOC_UNUSED,
else if (nbytes == 4 && suffix == ELF_SUFFIX_GOTOFF) [ELF_SUFFIX_GOTOFF] BFD_RELOC_16_GOTOFF,
reloc = BFD_RELOC_32_GOTOFF; [ELF_SUFFIX_GOTPLT] BFD_RELOC_UNUSED,
else if (nbytes == 8 && suffix == ELF_SUFFIX_GOTOFF) [ELF_SUFFIX_PLTOFF] BFD_RELOC_390_PLTOFF16,
reloc = BFD_RELOC_390_GOTOFF64; [ELF_SUFFIX_TLS_GD] BFD_RELOC_UNUSED,
else if (nbytes == 2 && suffix == ELF_SUFFIX_PLTOFF) [ELF_SUFFIX_TLS_GOTIE] BFD_RELOC_UNUSED,
reloc = BFD_RELOC_390_PLTOFF16; [ELF_SUFFIX_TLS_IE] BFD_RELOC_UNUSED,
else if (nbytes == 4 && suffix == ELF_SUFFIX_PLTOFF) [ELF_SUFFIX_TLS_LDM] BFD_RELOC_UNUSED,
reloc = BFD_RELOC_390_PLTOFF32; [ELF_SUFFIX_TLS_LDO] BFD_RELOC_UNUSED,
else if (nbytes == 8 && suffix == ELF_SUFFIX_PLTOFF) [ELF_SUFFIX_TLS_LE] BFD_RELOC_UNUSED,
reloc = BFD_RELOC_390_PLTOFF64; };
else if (nbytes == 4 && suffix == ELF_SUFFIX_PLT) reloc = tab2[suffix];
reloc = BFD_RELOC_390_PLT32; }
else if (nbytes == 8 && suffix == ELF_SUFFIX_PLT) else if (nbytes == 4)
reloc = BFD_RELOC_390_PLT64; {
else if (nbytes == 4 && suffix == ELF_SUFFIX_GOTPLT) static bfd_reloc_code_real_type tab4[] =
reloc = BFD_RELOC_390_GOTPLT32; {
else if (nbytes == 8 && suffix == ELF_SUFFIX_GOTPLT) [ELF_SUFFIX_NONE] BFD_RELOC_UNUSED ,
reloc = BFD_RELOC_390_GOTPLT64; [ELF_SUFFIX_GOT] BFD_RELOC_32_GOT_PCREL,
[ELF_SUFFIX_PLT] BFD_RELOC_390_PLT32,
[ELF_SUFFIX_GOTENT] BFD_RELOC_UNUSED,
[ELF_SUFFIX_GOTOFF] BFD_RELOC_32_GOTOFF,
[ELF_SUFFIX_GOTPLT] BFD_RELOC_390_GOTPLT32,
[ELF_SUFFIX_PLTOFF] BFD_RELOC_390_PLTOFF32,
[ELF_SUFFIX_TLS_GD] BFD_RELOC_390_TLS_GD32,
[ELF_SUFFIX_TLS_GOTIE] BFD_RELOC_390_TLS_GOTIE32,
[ELF_SUFFIX_TLS_IE] BFD_RELOC_390_TLS_IE32,
[ELF_SUFFIX_TLS_LDM] BFD_RELOC_390_TLS_LDM32,
[ELF_SUFFIX_TLS_LDO] BFD_RELOC_390_TLS_LDO32,
[ELF_SUFFIX_TLS_LE] BFD_RELOC_390_TLS_LE32,
};
reloc = tab4[suffix];
}
else if (nbytes == 8)
{
static bfd_reloc_code_real_type tab8[] =
{
[ELF_SUFFIX_NONE] BFD_RELOC_UNUSED ,
[ELF_SUFFIX_GOT] BFD_RELOC_390_GOT64,
[ELF_SUFFIX_PLT] BFD_RELOC_390_PLT64,
[ELF_SUFFIX_GOTENT] BFD_RELOC_UNUSED,
[ELF_SUFFIX_GOTOFF] BFD_RELOC_390_GOTOFF64,
[ELF_SUFFIX_GOTPLT] BFD_RELOC_390_GOTPLT64,
[ELF_SUFFIX_PLTOFF] BFD_RELOC_390_PLTOFF64,
[ELF_SUFFIX_TLS_GD] BFD_RELOC_390_TLS_GD64,
[ELF_SUFFIX_TLS_GOTIE] BFD_RELOC_390_TLS_GOTIE64,
[ELF_SUFFIX_TLS_IE] BFD_RELOC_390_TLS_IE64,
[ELF_SUFFIX_TLS_LDM] BFD_RELOC_390_TLS_LDM64,
[ELF_SUFFIX_TLS_LDO] BFD_RELOC_390_TLS_LDO64,
[ELF_SUFFIX_TLS_LE] BFD_RELOC_390_TLS_LE64,
};
reloc = tab8[suffix];
}
else else
reloc = BFD_RELOC_UNUSED; reloc = BFD_RELOC_UNUSED;
if (reloc != BFD_RELOC_UNUSED) if (reloc != BFD_RELOC_UNUSED
&& (reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc)))
{ {
reloc_howto = bfd_reloc_type_lookup (stdoutput, reloc);
size = bfd_get_reloc_size (reloc_howto); size = bfd_get_reloc_size (reloc_howto);
if (size > nbytes) if (size > nbytes)
as_bad (_("%s relocations do not fit in %d bytes"), as_bad (_("%s relocations do not fit in %d bytes"),
@@ -1035,6 +1142,7 @@ md_gather_operands (str, insn, opcode)
struct s390_fixup fixups[MAX_INSN_FIXUPS]; struct s390_fixup fixups[MAX_INSN_FIXUPS];
const struct s390_operand *operand; const struct s390_operand *operand;
const unsigned char *opindex_ptr; const unsigned char *opindex_ptr;
expressionS ex;
elf_suffix_type suffix; elf_suffix_type suffix;
bfd_reloc_code_real_type reloc; bfd_reloc_code_real_type reloc;
int skip_optional; int skip_optional;
@@ -1052,7 +1160,6 @@ md_gather_operands (str, insn, opcode)
fc = 0; fc = 0;
for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++) for (opindex_ptr = opcode->operands; *opindex_ptr != 0; opindex_ptr++)
{ {
expressionS ex;
char *hold; char *hold;
operand = s390_operands + *opindex_ptr; operand = s390_operands + *opindex_ptr;
@@ -1167,6 +1274,18 @@ md_gather_operands (str, insn, opcode)
&& (operand->bits == 32)) && (operand->bits == 32))
reloc = BFD_RELOC_390_GOTPLTENT; reloc = BFD_RELOC_390_GOTPLTENT;
} }
else if (suffix == ELF_SUFFIX_TLS_GOTIE)
{
if ((operand->flags & S390_OPERAND_DISP)
&& (operand->bits == 12))
reloc = BFD_RELOC_390_TLS_GOTIE12;
}
else if (suffix == ELF_SUFFIX_TLS_IE)
{
if ((operand->flags & S390_OPERAND_PCREL)
&& (operand->bits == 32))
reloc = BFD_RELOC_390_TLS_IEENT;
}
if (suffix != ELF_SUFFIX_NONE && reloc == BFD_RELOC_UNUSED) if (suffix != ELF_SUFFIX_NONE && reloc == BFD_RELOC_UNUSED)
as_bad (_("invalid operand suffix")); as_bad (_("invalid operand suffix"));
@@ -1262,6 +1381,20 @@ md_gather_operands (str, insn, opcode)
while (ISSPACE (*str)) while (ISSPACE (*str))
++str; ++str;
/* Check for tls instruction marker. */
reloc = s390_tls_suffix (&str, &ex);
if (reloc != BFD_RELOC_UNUSED)
{
/* We need to generate a fixup of type 'reloc' for this
instruction. */
if (fc >= MAX_INSN_FIXUPS)
as_fatal (_("too many fixups"));
fixups[fc].exp = ex;
fixups[fc].opindex = -1;
fixups[fc].reloc = reloc;
++fc;
}
if (*str != '\0') if (*str != '\0')
{ {
char *linefeed; char *linefeed;
@@ -1286,6 +1419,15 @@ md_gather_operands (str, insn, opcode)
md_apply_fix3. */ md_apply_fix3. */
for (i = 0; i < fc; i++) for (i = 0; i < fc; i++)
{ {
if (fixups[i].opindex < 0)
{
/* Create tls instruction marker relocation. */
fix_new_exp (frag_now, f - frag_now->fr_literal, opcode->oplen,
&fixups[i].exp, 0, fixups[i].reloc);
continue;
}
operand = s390_operands + fixups[i].opindex; operand = s390_operands + fixups[i].opindex;
if (fixups[i].reloc != BFD_RELOC_UNUSED) if (fixups[i].reloc != BFD_RELOC_UNUSED)
@@ -1699,6 +1841,26 @@ tc_s390_fix_adjustable (fixP)
|| fixP->fx_r_type == BFD_RELOC_390_GOTPLT32 || fixP->fx_r_type == BFD_RELOC_390_GOTPLT32
|| fixP->fx_r_type == BFD_RELOC_390_GOTPLT64 || fixP->fx_r_type == BFD_RELOC_390_GOTPLT64
|| fixP->fx_r_type == BFD_RELOC_390_GOTPLTENT || fixP->fx_r_type == BFD_RELOC_390_GOTPLTENT
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LOAD
|| fixP->fx_r_type == BFD_RELOC_390_TLS_GDCALL
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LDCALL
|| fixP->fx_r_type == BFD_RELOC_390_TLS_GD32
|| fixP->fx_r_type == BFD_RELOC_390_TLS_GD64
|| fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE12
|| fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE32
|| fixP->fx_r_type == BFD_RELOC_390_TLS_GOTIE64
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LDM32
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LDM64
|| fixP->fx_r_type == BFD_RELOC_390_TLS_IE32
|| fixP->fx_r_type == BFD_RELOC_390_TLS_IE64
|| fixP->fx_r_type == BFD_RELOC_390_TLS_IEENT
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LE32
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LE64
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LDO32
|| fixP->fx_r_type == BFD_RELOC_390_TLS_LDO64
|| fixP->fx_r_type == BFD_RELOC_390_TLS_DTPMOD
|| fixP->fx_r_type == BFD_RELOC_390_TLS_DTPOFF
|| fixP->fx_r_type == BFD_RELOC_390_TLS_TPOFF
|| fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
|| fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY) || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
return 0; return 0;
@@ -1973,6 +2135,32 @@ md_apply_fix3 (fixP, valP, seg)
fixP->fx_done = 0; fixP->fx_done = 0;
return; return;
case BFD_RELOC_390_TLS_LOAD:
case BFD_RELOC_390_TLS_GDCALL:
case BFD_RELOC_390_TLS_LDCALL:
case BFD_RELOC_390_TLS_GD32:
case BFD_RELOC_390_TLS_GD64:
case BFD_RELOC_390_TLS_GOTIE12:
case BFD_RELOC_390_TLS_GOTIE32:
case BFD_RELOC_390_TLS_GOTIE64:
case BFD_RELOC_390_TLS_LDM32:
case BFD_RELOC_390_TLS_LDM64:
case BFD_RELOC_390_TLS_IE32:
case BFD_RELOC_390_TLS_IE64:
case BFD_RELOC_390_TLS_LE32:
case BFD_RELOC_390_TLS_LE64:
case BFD_RELOC_390_TLS_LDO32:
case BFD_RELOC_390_TLS_LDO64:
case BFD_RELOC_390_TLS_DTPMOD:
case BFD_RELOC_390_TLS_DTPOFF:
case BFD_RELOC_390_TLS_TPOFF:
/* Fully resolved at link time. */
break;
case BFD_RELOC_390_TLS_IEENT:
/* Fully resolved at link time. */
value += 2;
break;
default: default:
{ {
const char *reloc_name = bfd_get_reloc_code_name (fixP->fx_r_type); const char *reloc_name = bfd_get_reloc_code_name (fixP->fx_r_type);