mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 18:08:24 +08:00
Handle Alpha load-immediate-FP pseudo-instructions:
* config/alpha-opcode.h (ldif, ldig, ldis, ldit): New patterns. * config/tc-alpha.c (lit8_sec, lit4_sec, lit8_sym, lit4_sym): New variables. (create_literal_section): New function. (create_lita_section): Now a macro. (get_lit8_offset, get_lit4_offset): New functions. (maybe_set_gp): New function. (select_gp_value): Call it. (load_expression): Preserve addend if symbol is a section symbol. (alpha_ip): Handle new operand type `F' for floating-point constants; store them in .lit{4,8} sections. (alpha_ip, case 'G'): Emit LITUSE relocations for symbol exprs.
This commit is contained in:
@ -394,6 +394,10 @@ static const struct alpha_opcode alpha_opcodes[] =
|
|||||||
{ "sts", 0x98000000, 1, "e,P" }, /* regbase macro */
|
{ "sts", 0x98000000, 1, "e,P" }, /* regbase macro */
|
||||||
{ "stt", 0x9c000000, 1, "e,l(2)" },
|
{ "stt", 0x9c000000, 1, "e,l(2)" },
|
||||||
{ "stt", 0x9c000000, 1, "e,P" }, /* regbase macro */
|
{ "stt", 0x9c000000, 1, "e,P" }, /* regbase macro */
|
||||||
|
{ "ldif", 0x80000000, 1, "e,F" },
|
||||||
|
{ "ldig", 0x84000000, 1, "e,F" },
|
||||||
|
{ "ldis", 0x88000000, 1, "e,F" },
|
||||||
|
{ "ldit", 0x8c000000, 1, "e,F" },
|
||||||
|
|
||||||
{ "fbeq", 0xc4000000, 1, "e,L" }, /* 6o+5a+21d */
|
{ "fbeq", 0xc4000000, 1, "e,L" }, /* 6o+5a+21d */
|
||||||
{ "fbne", 0xd4000000, 1, "e,L" },
|
{ "fbne", 0xd4000000, 1, "e,L" },
|
||||||
|
@ -70,10 +70,11 @@ int md_long_jump_size = 4;
|
|||||||
/* handle of the OPCODE hash table */
|
/* handle of the OPCODE hash table */
|
||||||
static struct hash_control *op_hash;
|
static struct hash_control *op_hash;
|
||||||
|
|
||||||
/* sections we'll want to keep track of */
|
/* Sections and symbols we'll want to keep track of. */
|
||||||
static segT lita_sec, rdata, sdata;
|
static segT lita_sec, rdata, sdata, lit8_sec, lit4_sec;
|
||||||
|
static symbolS *lit8_sym, *lit4_sym;
|
||||||
|
|
||||||
/* setting for ".set [no]{at,macro}" */
|
/* Setting for ".set [no]{at,macro}". */
|
||||||
static int at_ok = 1, macro_ok = 1;
|
static int at_ok = 1, macro_ok = 1;
|
||||||
|
|
||||||
/* Keep track of global pointer. */
|
/* Keep track of global pointer. */
|
||||||
@ -431,17 +432,54 @@ s_gprel32 ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
create_lita_section ()
|
create_literal_section (secp, name)
|
||||||
|
segT *secp;
|
||||||
|
const char *name;
|
||||||
{
|
{
|
||||||
segT current_section = now_seg;
|
segT current_section = now_seg;
|
||||||
int current_subsec = now_subseg;
|
int current_subsec = now_subseg;
|
||||||
|
segT new_sec;
|
||||||
|
|
||||||
lita_sec = subseg_new (".lita", 0);
|
*secp = new_sec = subseg_new (name, 0);
|
||||||
subseg_set (current_section, current_subsec);
|
subseg_set (current_section, current_subsec);
|
||||||
bfd_set_section_flags (stdoutput, lita_sec,
|
bfd_set_section_alignment (stdoutput, new_sec, 3);
|
||||||
|
bfd_set_section_flags (stdoutput, new_sec,
|
||||||
SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY
|
SEC_RELOC | SEC_ALLOC | SEC_LOAD | SEC_READONLY
|
||||||
| SEC_DATA);
|
| SEC_DATA);
|
||||||
bfd_set_section_alignment (stdoutput, lita_sec, 3);
|
}
|
||||||
|
|
||||||
|
#define create_lita_section() create_literal_section (&lita_sec, ".lita")
|
||||||
|
|
||||||
|
static valueT
|
||||||
|
get_lit8_offset (val)
|
||||||
|
bfd_vma val;
|
||||||
|
{
|
||||||
|
valueT retval;
|
||||||
|
if (lit8_sec == 0)
|
||||||
|
{
|
||||||
|
create_literal_section (&lit8_sec, ".lit8");
|
||||||
|
lit8_sym = section_symbol (lit8_sec);
|
||||||
|
}
|
||||||
|
retval = add_to_literal_pool ((symbolS *) 0, val, lit8_sec, 8);
|
||||||
|
if (retval >= 0xfff0)
|
||||||
|
as_fatal ("overflow in fp literal (.lit8) table");
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static valueT
|
||||||
|
get_lit4_offset (val)
|
||||||
|
bfd_vma val;
|
||||||
|
{
|
||||||
|
valueT retval;
|
||||||
|
if (lit4_sec == 0)
|
||||||
|
{
|
||||||
|
create_literal_section (&lit4_sec, ".lit4");
|
||||||
|
lit4_sym = section_symbol (lit4_sec);
|
||||||
|
}
|
||||||
|
retval = add_to_literal_pool ((symbolS *) 0, val, lit4_sec, 4);
|
||||||
|
if (retval >= 0xfff0)
|
||||||
|
as_fatal ("overflow in fp literal (.lit4) table");
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This function is called once, at assembler startup time. It should
|
/* This function is called once, at assembler startup time. It should
|
||||||
@ -510,7 +548,6 @@ md_begin ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (lose)
|
if (lose)
|
||||||
as_fatal ("Broken assembler. No assembly attempted.");
|
as_fatal ("Broken assembler. No assembly attempted.");
|
||||||
|
|
||||||
@ -578,31 +615,34 @@ md_assemble (str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
maybe_set_gp (sec)
|
||||||
|
asection *sec;
|
||||||
|
{
|
||||||
|
bfd_vma vma;
|
||||||
|
if (!sec)
|
||||||
|
return;
|
||||||
|
vma = bfd_get_section_vma (foo, sec);
|
||||||
|
if (vma && vma < alpha_gp_value)
|
||||||
|
alpha_gp_value = vma;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
select_gp_value ()
|
select_gp_value ()
|
||||||
{
|
{
|
||||||
bfd_vma lita_vma, sdata_vma;
|
|
||||||
|
|
||||||
if (alpha_gp_value != 0)
|
if (alpha_gp_value != 0)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
if (lita_sec)
|
/* Get minus-one in whatever width... */
|
||||||
lita_vma = bfd_get_section_vma (abfd, lita_sec);
|
alpha_gp_value = 0; alpha_gp_value--;
|
||||||
else
|
|
||||||
lita_vma = 0;
|
|
||||||
#if 0
|
|
||||||
if (sdata)
|
|
||||||
sdata_vma = bfd_get_section_vma (abfd, sdata);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
sdata = 0;
|
|
||||||
|
|
||||||
if (lita_vma == 0
|
/* Select the smallest VMA of these existing sections. */
|
||||||
/* Who knows which order they'll get laid out in? */
|
maybe_set_gp (lita_sec);
|
||||||
|| (sdata_vma != 0 && sdata_vma < lita_vma))
|
/* maybe_set_gp (sdata); Was disabled before -- should we use it? */
|
||||||
alpha_gp_value = sdata_vma;
|
#if 0
|
||||||
else
|
maybe_set_gp (lit8_sec);
|
||||||
alpha_gp_value = lita_vma;
|
maybe_set_gp (lit4_sec);
|
||||||
|
#endif
|
||||||
|
|
||||||
alpha_gp_value += GP_ADJUSTMENT;
|
alpha_gp_value += GP_ADJUSTMENT;
|
||||||
|
|
||||||
@ -747,8 +787,15 @@ load_expression (reg, insn)
|
|||||||
valueT addend;
|
valueT addend;
|
||||||
int num_insns = 1;
|
int num_insns = 1;
|
||||||
|
|
||||||
|
if (insn->reloc[0].exp.X_add_symbol->bsym->flags & BSF_SECTION_SYM)
|
||||||
|
{
|
||||||
|
addend = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
addend = insn->reloc[0].exp.X_add_number;
|
addend = insn->reloc[0].exp.X_add_number;
|
||||||
insn->reloc[0].exp.X_add_number = 0;
|
insn->reloc[0].exp.X_add_number = 0;
|
||||||
|
}
|
||||||
load_symbol_address (reg, insn);
|
load_symbol_address (reg, insn);
|
||||||
if (addend)
|
if (addend)
|
||||||
{
|
{
|
||||||
@ -1165,6 +1212,60 @@ alpha_ip (str, insns)
|
|||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case 'F':
|
||||||
|
{
|
||||||
|
int format, length, mode, i, size;
|
||||||
|
char temp[20 /*MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT*/];
|
||||||
|
char *err;
|
||||||
|
static const char formats[4] = "FGfd";
|
||||||
|
bfd_vma bits, offset;
|
||||||
|
char *old_input_line_pointer = input_line_pointer;
|
||||||
|
|
||||||
|
input_line_pointer = s;
|
||||||
|
SKIP_WHITESPACE ();
|
||||||
|
memset (temp, 0, sizeof (temp));
|
||||||
|
mode = (opcode >> 26) & 3;
|
||||||
|
format = formats[mode];
|
||||||
|
err = md_atof (format, temp, &length);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
as_bad ("Bad floating literal: %s", err);
|
||||||
|
bits = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Generate little-endian number from byte sequence. */
|
||||||
|
bits = 0;
|
||||||
|
for (i = length - 1; i >= 0; i--)
|
||||||
|
bits += ((bfd_vma)(temp[i] & 0xff)) << (i * 8);
|
||||||
|
}
|
||||||
|
switch (length)
|
||||||
|
{
|
||||||
|
case 8:
|
||||||
|
offset = get_lit8_offset (bits) - 0x8000;
|
||||||
|
insns[0].reloc[0].exp.X_add_symbol = lit8_sym;
|
||||||
|
insns[0].reloc[0].exp.X_add_number = 0x8000;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
offset = get_lit4_offset (bits) - 0x8000;
|
||||||
|
insns[0].reloc[0].exp.X_add_symbol = lit4_sym;
|
||||||
|
insns[0].reloc[0].exp.X_add_number = 0x8000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
insns[0].reloc[0].exp.X_op = O_symbol;
|
||||||
|
offset &= 0xffff;
|
||||||
|
num_gen = load_expression (AT, &insns[0]);
|
||||||
|
insns[num_gen].reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
|
||||||
|
insns[num_gen].reloc[0].exp = lituse_basereg;
|
||||||
|
insns[num_gen++].opcode = opcode | (AT << SB) | offset;
|
||||||
|
opcode = insns[0].opcode;
|
||||||
|
s = input_line_pointer;
|
||||||
|
input_line_pointer = old_input_line_pointer;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
/* The following two.. take advantage of the fact that
|
/* The following two.. take advantage of the fact that
|
||||||
opcode already contains most of what we need to know.
|
opcode already contains most of what we need to know.
|
||||||
We just prepend to the instr an "ldah
|
We just prepend to the instr an "ldah
|
||||||
@ -1246,8 +1347,10 @@ alpha_ip (str, insns)
|
|||||||
{
|
{
|
||||||
struct alpha_it *i;
|
struct alpha_it *i;
|
||||||
i = &insns[num_gen++];
|
i = &insns[num_gen++];
|
||||||
i->reloc[0].code = BFD_RELOC_NONE;
|
|
||||||
i->opcode = old_opcode | (tmp_reg << SB);
|
i->opcode = old_opcode | (tmp_reg << SB);
|
||||||
|
|
||||||
|
i->reloc[0].code = BFD_RELOC_ALPHA_LITUSE;
|
||||||
|
i->reloc[0].exp = lituse_basereg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user