diff options
author | Thiemo Seufer <ths@networkno.de> | 2002-05-30 23:32:47 +0000 |
---|---|---|
committer | Thiemo Seufer <ths@networkno.de> | 2002-05-30 23:32:47 +0000 |
commit | 438c16b8759036fe9e9ecd48d71f4a3b4bc31a5a (patch) | |
tree | e5d8f09d344ab6f3aa501a96731a8a6066069a31 /gas/config | |
parent | ee8ff470c4c1c850ebe9f7f09695ca8be0a21540 (diff) | |
download | gdb-438c16b8759036fe9e9ecd48d71f4a3b4bc31a5a.zip gdb-438c16b8759036fe9e9ecd48d71f4a3b4bc31a5a.tar.gz gdb-438c16b8759036fe9e9ecd48d71f4a3b4bc31a5a.tar.bz2 |
* config/tc-mips.c (macro_build_jalr): New Function.
(md_begin): NewABI uses big GOTs.
(macro_build): Recognize BFD_RELOC_MIPS_GOT_DISP,
BFD_RELOC_MIPS_GOT_PAGE, BFD_RELOC_MIPS_GOT_OFST as valid.
(load_address): Add some NewABI PIC support.
(macro): Likewise.
(md_apply_fix): Special handling for BFD_RELOC_MIPS_JALR.
(tc_gen_reloc): Don't encode NewABI vtables in REL relocations.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-mips.c | 272 |
1 files changed, 190 insertions, 82 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index c9ec497..47199f7 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -697,6 +697,7 @@ static void macro_build (); static void mips16_macro_build PARAMS ((char *, int *, expressionS *, const char *, const char *, va_list)); +static void macro_build_jalr PARAMS ((int, expressionS *)); static void macro_build_lui PARAMS ((char *place, int *counter, expressionS * ep, int regnum)); static void set_at PARAMS ((int *counter, int reg, int unsignedp)); @@ -1255,6 +1256,9 @@ md_begin () mips_opts.gp32 = file_mips_gp32; mips_opts.fp32 = file_mips_fp32; + if (HAVE_NEWABI) + mips_big_got = 1; + op_hash = hash_new (); for (i = 0; i < NUMOPCODES;) @@ -3014,6 +3018,9 @@ macro_build (place, counter, ep, name, fmt, va_alist) || *r == BFD_RELOC_LO16 || *r == BFD_RELOC_MIPS_GOT16 || *r == BFD_RELOC_MIPS_CALL16 + || *r == BFD_RELOC_MIPS_GOT_DISP + || *r == BFD_RELOC_MIPS_GOT_PAGE + || *r == BFD_RELOC_MIPS_GOT_OFST || *r == BFD_RELOC_MIPS_GOT_LO16 || *r == BFD_RELOC_MIPS_CALL_LO16 || (ep->X_op == O_subtract @@ -3203,6 +3210,23 @@ mips16_macro_build (place, counter, ep, name, fmt, args) } /* + * Generate a "jalr" instruction with a relocation hint to the called + * function. This occurs in NewABI PIC code. + */ +static void +macro_build_jalr (icnt, ep) + int icnt; + expressionS *ep; +{ + if (HAVE_NEWABI) + frag_more (0); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s", + RA, PIC_CALL_REG); + if (HAVE_NEWABI) + fix_new_exp (frag_now, 0, 0, ep, false, BFD_RELOC_MIPS_JALR); +} + +/* * Generate a "lui" instruction. */ static void @@ -3815,43 +3839,60 @@ load_address (counter, reg, ep, used_at) lw $reg,<sym>($gp) (BFD_RELOC_MIPS_GOT16) nop addiu $reg,$reg,<sym> (BFD_RELOC_LO16) + If we have NewABI, we want + lw $reg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE) + addiu $reg,$reg,<sym> (BFD_RELOC_MIPS_GOT_OFST) If there is a constant, it must be added in after. */ ex.X_add_number = ep->X_add_number; ep->X_add_number = 0; - if (reg_needs_delay (mips_gp_register)) - off = 4; + if (HAVE_NEWABI) + { + macro_build ((char *) NULL, counter, ep, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg, + (int) BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register); + macro_build (p, counter, ep, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j", + reg, reg, (int) BFD_RELOC_MIPS_GOT_OFST); + } else - off = 0; - frag_grow (32); - macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg, - (int) BFD_RELOC_MIPS_GOT_HI16); - macro_build ((char *) NULL, counter, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", "d,v,t", reg, - reg, mips_gp_register); - macro_build ((char *) NULL, counter, ep, - HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg, - (int) BFD_RELOC_MIPS_GOT_LO16, reg); - p = frag_var (rs_machine_dependent, 12 + off, 0, - RELAX_ENCODE (12, 12 + off, off, 8 + off, 0, - mips_opts.warn_about_macros), - ep->X_add_symbol, 0, NULL); - if (off > 0) - { - /* We need a nop before loading from $gp. This special - check is required because the lui which starts the main - instruction stream does not refer to $gp, and so will not - insert the nop which may be required. */ + { + if (reg_needs_delay (mips_gp_register)) + off = 4; + else + off = 0; + frag_grow (32); + macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg, + (int) BFD_RELOC_MIPS_GOT_HI16); + macro_build ((char *) NULL, counter, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "addu" : "daddu", "d,v,t", reg, + reg, mips_gp_register); + macro_build ((char *) NULL, counter, ep, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT_LO16, reg); + p = frag_var (rs_machine_dependent, 12 + off, 0, + RELAX_ENCODE (12, 12 + off, off, 8 + off, 0, + mips_opts.warn_about_macros), + ep->X_add_symbol, 0, NULL); + if (off > 0) + { + /* We need a nop before loading from $gp. This special + check is required because the lui which starts the main + instruction stream does not refer to $gp, and so will not + insert the nop which may be required. */ + macro_build (p, counter, (expressionS *) NULL, "nop", ""); + p += 4; + } + macro_build (p, counter, ep, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg, + (int) BFD_RELOC_MIPS_GOT16, mips_gp_register); + p += 4; macro_build (p, counter, (expressionS *) NULL, "nop", ""); p += 4; + macro_build (p, counter, ep, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", reg, reg, (int) BFD_RELOC_LO16); } - macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "lw" : "ld", - "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, - mips_gp_register); - p += 4; - macro_build (p, counter, (expressionS *) NULL, "nop", ""); - p += 4; - macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", - "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + if (ex.X_add_number != 0) { if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000) @@ -4940,7 +4981,32 @@ macro (ip) lui $at,<hiconstant> addiu $at,$at,<loconstant> (BFD_RELOC_LO16) addu $tempreg,$tempreg,$at - */ + + For NewABI, we want for data addresses + lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_DISP) + If tempreg is PIC_CALL_REG pointing to a external symbol, we want + lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_CALL16) + */ + if (HAVE_NEWABI) + { + int reloc_type = (tempreg == PIC_CALL_REG + ? BFD_RELOC_MIPS_CALL16 + : BFD_RELOC_MIPS_GOT_DISP); + + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, reloc_type, mips_gp_register); + + if (breg != 0) + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + "d,v,t", treg, tempreg, breg); + + if (! used_at) + return; + + break; + } expr1.X_add_number = offset_expr.X_add_number; offset_expr.X_add_number = 0; frag_grow (52); @@ -5229,65 +5295,78 @@ macro (ip) addiu $25,$25,<sym> (BFD_RELOC_LO16) jalr $ra,$25 nop - lw $gp,cprestore($sp) */ - frag_grow (40); - if (! mips_big_got) + lw $gp,cprestore($sp) + For NewABI, we want + lw $25,<sym>($gp) (BFD_RELOC_MIPS_GOT_DISP) + jalr $ra,$25 (BFD_RELOC_MIPS_JALR) + */ + if (HAVE_NEWABI) { macro_build ((char *) NULL, &icnt, &offset_expr, HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", PIC_CALL_REG, - (int) BFD_RELOC_MIPS_CALL16, mips_gp_register); - macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - "nop", ""); - p = frag_var (rs_machine_dependent, 4, 0, - RELAX_ENCODE (0, 4, -8, 0, 0, 0), - offset_expr.X_add_symbol, 0, NULL); + (int) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register); + macro_build_jalr (icnt, &offset_expr); } else { - int gpdel; - - if (reg_needs_delay (mips_gp_register)) - gpdel = 4; + frag_grow (40); + if (! mips_big_got) + { + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", PIC_CALL_REG, + (int) BFD_RELOC_MIPS_CALL16, mips_gp_register); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + "nop", ""); + p = frag_var (rs_machine_dependent, 4, 0, + RELAX_ENCODE (0, 4, -8, 0, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + } else - gpdel = 0; - macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u", - PIC_CALL_REG, (int) BFD_RELOC_MIPS_CALL_HI16); - macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", - "d,v,t", PIC_CALL_REG, PIC_CALL_REG, - mips_gp_register); - macro_build ((char *) NULL, &icnt, &offset_expr, - HAVE_32BIT_ADDRESSES ? "lw" : "ld", - "t,o(b)", PIC_CALL_REG, - (int) BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG); - macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - "nop", ""); - p = frag_var (rs_machine_dependent, 12 + gpdel, 0, - RELAX_ENCODE (16, 12 + gpdel, gpdel, 8 + gpdel, - 0, 0), - offset_expr.X_add_symbol, 0, NULL); - if (gpdel > 0) { + int gpdel; + + if (reg_needs_delay (mips_gp_register)) + gpdel = 4; + else + gpdel = 0; + macro_build ((char *) NULL, &icnt, &offset_expr, "lui", + "t,u", PIC_CALL_REG, + (int) BFD_RELOC_MIPS_CALL_HI16); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + "d,v,t", PIC_CALL_REG, PIC_CALL_REG, + mips_gp_register); + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", PIC_CALL_REG, + (int) BFD_RELOC_MIPS_CALL_LO16, PIC_CALL_REG); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + "nop", ""); + p = frag_var (rs_machine_dependent, 12 + gpdel, 0, + RELAX_ENCODE (16, 12 + gpdel, gpdel, + 8 + gpdel, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + if (gpdel > 0) + { + macro_build (p, &icnt, (expressionS *) NULL, "nop", ""); + p += 4; + } + macro_build (p, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", PIC_CALL_REG, + (int) BFD_RELOC_MIPS_GOT16, mips_gp_register); + p += 4; macro_build (p, &icnt, (expressionS *) NULL, "nop", ""); p += 4; } macro_build (p, &icnt, &offset_expr, - HAVE_32BIT_ADDRESSES ? "lw" : "ld", - "t,o(b)", PIC_CALL_REG, - (int) BFD_RELOC_MIPS_GOT16, mips_gp_register); - p += 4; - macro_build (p, &icnt, (expressionS *) NULL, "nop", ""); - p += 4; - } - macro_build (p, &icnt, &offset_expr, - HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", - "t,r,j", PIC_CALL_REG, PIC_CALL_REG, - (int) BFD_RELOC_LO16); - macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - "jalr", "s", PIC_CALL_REG); - if (! HAVE_NEWABI) - { + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", PIC_CALL_REG, PIC_CALL_REG, + (int) BFD_RELOC_LO16); + macro_build_jalr (icnt, &offset_expr); + if (mips_cprestore_offset < 0) as_warn (_("No .cprestore pseudo-op used in PIC code")); else @@ -5782,13 +5861,41 @@ macro (ip) <op> instruction. We don't handle constants larger than 16 bits, because we have no way to load the upper 16 bits (actually, we could handle them for the subset of cases - in which we are not using $at). */ + in which we are not using $at). + + For NewABI, we want + lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT_PAGE) + addiu $tempreg,$tempreg,<sym> (BFD_RELOC_MIPS_GOT_OFST) + <op> $treg,0($tempreg) + */ assert (offset_expr.X_op == O_symbol); expr1.X_add_number = offset_expr.X_add_number; offset_expr.X_add_number = 0; if (expr1.X_add_number < -0x8000 || expr1.X_add_number >= 0x8000) as_bad (_("PIC code offset overflow (max 16 signed bits)")); + if (HAVE_NEWABI) + { + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, BFD_RELOC_MIPS_GOT_PAGE, + mips_gp_register); + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", tempreg, tempreg, + BFD_RELOC_MIPS_GOT_OFST); + if (breg != 0) + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + "d,v,t", tempreg, tempreg, breg); + macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg, + (int) BFD_RELOC_LO16, tempreg); + + if (! used_at) + return; + + break; + } if (reg_needs_delay (mips_gp_register)) gpdel = 4; else @@ -10623,7 +10730,8 @@ md_apply_fix3 (fixP, valP, seg) || fixP->fx_r_type == BFD_RELOC_MIPS_REL16 || fixP->fx_r_type == BFD_RELOC_MIPS_RELGOT || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY); + || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixP->fx_r_type == BFD_RELOC_MIPS_JALR); value = *valP; @@ -12580,9 +12688,9 @@ tc_gen_reloc (section, fixp) abort (); } - /* Since MIPS ELF uses Rel instead of Rela, encode the vtable entry - to be used in the relocation's section offset. */ - if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) + /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable + entry to be used in the relocation's section offset. */ + if (! HAVE_NEWABI && fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) { reloc->address = reloc->addend; reloc->addend = 0; |