From 438c16b8759036fe9e9ecd48d71f4a3b4bc31a5a Mon Sep 17 00:00:00 2001 From: Thiemo Seufer Date: Thu, 30 May 2002 23:32:47 +0000 Subject: [PATCH] * 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. --- gas/ChangeLog | 11 ++ gas/config/tc-mips.c | 272 ++++++++++++++++++++++++++++++------------- 2 files changed, 201 insertions(+), 82 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index 6f3d2bddd8a..80a0db7303f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +2002-05-31 Thiemo Seufer + + * 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. + 2002-05-31 Thiemo Seufer * config/tc-mips.c (load_address): Use mips_gp_register instead diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index c9ec49709a9..47199f753b5 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 @@ -3202,6 +3209,23 @@ mips16_macro_build (place, counter, ep, name, fmt, args) append_insn (place, &insn, ep, r, false); } +/* + * 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. */ @@ -3815,43 +3839,60 @@ load_address (counter, reg, ep, used_at) lw $reg,($gp) (BFD_RELOC_MIPS_GOT16) nop addiu $reg,$reg, (BFD_RELOC_LO16) + If we have NewABI, we want + lw $reg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) + addiu $reg,$reg, (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, addiu $at,$at, (BFD_RELOC_LO16) addu $tempreg,$tempreg,$at - */ + + For NewABI, we want for data addresses + lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) + If tempreg is PIC_CALL_REG pointing to a external symbol, we want + lw $tempreg,($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, (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,($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) 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,($gp) (BFD_RELOC_MIPS_GOT_PAGE) + addiu $tempreg,$tempreg, (BFD_RELOC_MIPS_GOT_OFST) + $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; -- 2.30.2