From f5040a92c5b78b41f33dc3488dc1820bc5f916a8 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Fri, 11 Apr 2003 01:56:50 +0000 Subject: * config/tc-mips.h (tc_frag_data_type, TC_FRAG_TYPE): New. * config/tc-mips.c: Use signed add for n32 address arithmetic. (append_insn): When filling delay slots with instructions that have fixups that tc_gen_reloc might consider modifyable in variant frags, start a new frag. (load_address): Generate GOT_DISP with of without offset depending on whether symbol is local. For -xgot, use GOT_PAGE/GOT_OFST or GOT_HI16/GOT_LO16. (macro) : Likewise. : In NewABI, use CALL16 or GOT_DISP for small got, CALL_HI16/CALL_LO16 or GOT_PAGE/GOT_OFST for big got. : In NewABI with small got, always use GOT_PAGE/GOT_OFST, with the latter in the load/store instruction. With big got, use GOT_HI16/GOT_LO16 or GOT_PAGE/GOT_OFST. (tc_gen_reloc): Adjust variant frags with GOT_DISP in NewABI. Add tc_frag_data.tc_fr_offset to addends. Decay CALL16, GOT_OFST and GOT_DISP to GOT_DISP in NewABI. (md_convert_frag): Use memmove for safe copying of overlapping regions. --- gas/ChangeLog | 23 ++ gas/config/tc-mips.c | 725 +++++++++++++++++++++++++++++++++++++++++---------- gas/config/tc-mips.h | 5 + 3 files changed, 614 insertions(+), 139 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index fff94ad..3300a8d 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,26 @@ +2003-04-10 Alexandre Oliva + + * config/tc-mips.h (tc_frag_data_type, TC_FRAG_TYPE): New. + * config/tc-mips.c: Use signed add for n32 address arithmetic. + (append_insn): When filling delay slots with instructions + that have fixups that tc_gen_reloc might consider modifyable + in variant frags, start a new frag. + (load_address): Generate GOT_DISP with of without offset + depending on whether symbol is local. For -xgot, use + GOT_PAGE/GOT_OFST or GOT_HI16/GOT_LO16. + (macro) : Likewise. + : In NewABI, use CALL16 or GOT_DISP for small got, + CALL_HI16/CALL_LO16 or GOT_PAGE/GOT_OFST for big got. + : In NewABI with small got, always use + GOT_PAGE/GOT_OFST, with the latter in the load/store + instruction. With big got, use GOT_HI16/GOT_LO16 or + GOT_PAGE/GOT_OFST. + (tc_gen_reloc): Adjust variant frags with GOT_DISP in NewABI. + Add tc_frag_data.tc_fr_offset to addends. Decay CALL16, + GOT_OFST and GOT_DISP to GOT_DISP in NewABI. + (md_convert_frag): Use memmove for safe copying of overlapping + regions. + 2003-04-09 Stephane Carrez * doc/c-m68hc11.texi (M68HC11-Opts): Document -m68hcs12, -mshort, diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 3204ce9..e8b1588 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -1631,6 +1631,7 @@ append_insn (place, ip, address_expr, reloc_type) char *f; fixS *fixp[3]; int nops = 0; + bfd_boolean force_new_frag = FALSE; /* Mark instruction labels in mips16 mode. */ mips16_mark_labels (); @@ -2606,6 +2607,18 @@ append_insn (place, ip, address_expr, reloc_type) prev_insn_fixp[2]->fx_frag = frag_now; prev_insn_fixp[2]->fx_where = f - frag_now->fr_literal; } + if (prev_insn_fixp[0] && HAVE_NEWABI + && prev_insn_frag != frag_now + && (prev_insn_fixp[0]->fx_r_type + == BFD_RELOC_MIPS_GOT_DISP + || (prev_insn_fixp[0]->fx_r_type + == BFD_RELOC_MIPS_CALL16))) + { + /* To avoid confusion in tc_gen_reloc, we must + ensure that this does not become a variant + frag. */ + force_new_frag = TRUE; + } if (fixp[0]) { fixp[0]->fx_frag = prev_insn_frag; @@ -2747,6 +2760,15 @@ append_insn (place, ip, address_expr, reloc_type) /* We just output an insn, so the next one doesn't have a label. */ mips_clear_insn_labels (); + + /* We must ensure that the frag to which an instruction that was + moved from a non-variant frag doesn't become a variant frag, + otherwise tc_gen_reloc may get confused. */ + if (force_new_frag) + { + frag_wane (frag_now); + frag_new (0); + } } /* This function forgets that there was any previous instruction or @@ -3395,7 +3417,8 @@ macro_build_ldst_constoffset (place, counter, ep, op, treg, breg) if (place != NULL) place += 4; macro_build (place, counter, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, AT, breg); if (place != NULL) place += 4; @@ -3883,7 +3906,8 @@ load_address (counter, reg, ep, used_at) { frag_grow (20); macro_build ((char *) NULL, counter, ep, - HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "addi" : "addiu" : "daddiu", "t,r,j", reg, mips_gp_register, (int) BFD_RELOC_GPREL16); p = frag_var (rs_machine_dependent, 8, 0, RELAX_ENCODE (4, 8, 0, 4, 0, @@ -3894,7 +3918,8 @@ load_address (counter, reg, ep, used_at) if (p != NULL) p += 4; macro_build (p, counter, ep, - HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "addi" : "addiu" : "daddiu", "t,r,j", reg, reg, (int) BFD_RELOC_LO16); } } @@ -3908,20 +3933,54 @@ load_address (counter, reg, ep, used_at) lw $reg,($gp) (BFD_RELOC_MIPS_GOT16) nop addiu $reg,$reg, (BFD_RELOC_LO16) + If there is a constant, it must be added in after. + If we have NewABI, we want - lw $reg,($gp) (BFD_RELOC_MIPS_GOT_DISP) - If there is a constant, it must be added in after. */ - ex.X_add_number = ep->X_add_number; - ep->X_add_number = 0; - frag_grow (20); + lw $reg,($gp) (BFD_RELOC_MIPS_GOT_DISP) + unless we're referencing a global symbol with a non-zero + offset, in which case cst must be added separately. */ if (HAVE_NEWABI) { - macro_build ((char *) NULL, counter, ep, + frag_grow (12); + + if (ep->X_add_number) + { + frag_now->tc_frag_data.tc_fr_offset = + ex.X_add_number = ep->X_add_number; + ep->X_add_number = 0; + macro_build ((char *) NULL, counter, ep, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg, + (int) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register); + if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000) + as_bad (_("PIC code offset overflow (max 16 signed bits)")); + ex.X_op = O_constant; + macro_build ((char *) NULL, counter, &ex, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (8, 4, 0, 0, 0, + mips_opts.warn_about_macros), + ep->X_add_symbol, 0, (char *) NULL); + ep->X_add_number = ex.X_add_number; + } + + macro_build (p, counter, ep, HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT_DISP, mips_gp_register); + + if (! p) + { + /* To avoid confusion in tc_gen_reloc, we must ensure + that this does not become a variant frag. */ + frag_wane (frag_now); + frag_new (0); + } } else { + ex.X_add_number = ep->X_add_number; + ep->X_add_number = 0; + frag_grow (20); macro_build ((char *) NULL, counter, ep, HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", reg, (int) BFD_RELOC_MIPS_GOT16, mips_gp_register); @@ -3932,16 +3991,16 @@ load_address (counter, reg, ep, used_at) 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) - as_bad (_("PIC code offset overflow (max 16 signed bits)")); - ex.X_op = O_constant; - macro_build ((char *) NULL, counter, &ex, - 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) + as_bad (_("PIC code offset overflow (max 16 signed bits)")); + ex.X_op = O_constant; + macro_build ((char *) NULL, counter, &ex, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + } } } else if (mips_pic == SVR4_PIC) @@ -3954,27 +4013,58 @@ load_address (counter, reg, ep, used_at) lui $reg, (BFD_RELOC_MIPS_GOT_HI16) addu $reg,$reg,$gp lw $reg,($reg) (BFD_RELOC_MIPS_GOT_LO16) - Otherwise, for a reference to a local symbol, we want + + Otherwise, for a reference to a local symbol in old ABI, we want lw $reg,($gp) (BFD_RELOC_MIPS_GOT16) nop addiu $reg,$reg, (BFD_RELOC_LO16) - If we have NewABI, we want + If there is a constant, it must be added in after. + + In the NewABI, for local symbols, with or without offsets, 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 (HAVE_NEWABI) { + frag_grow (24); + + frag_now->tc_frag_data.tc_fr_offset = + ex.X_add_number = ep->X_add_number; + ep->X_add_number = 0; + 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 ? "add" : "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); + if (ex.X_add_number < -0x8000 || ex.X_add_number >= 0x8000) + as_bad (_("PIC code offset overflow (max 16 signed bits)")); + else if (ex.X_add_number) + { + ex.X_op = O_constant; + macro_build ((char *) NULL, counter, &ex, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + } + + ep->X_add_number = ex.X_add_number; + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (ex.X_add_number ? 16 : 12, 8, 0, 4, 0, + mips_opts.warn_about_macros), + ep->X_add_symbol, 0, (char *) NULL); + macro_build (p, 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", + macro_build (p + 4, counter, ep, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", "t,r,j", reg, reg, (int) BFD_RELOC_MIPS_GOT_OFST); } else { + ex.X_add_number = ep->X_add_number; + ep->X_add_number = 0; if (reg_needs_delay (mips_gp_register)) off = 4; else @@ -4010,16 +4100,16 @@ load_address (counter, reg, ep, used_at) 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) - as_bad (_("PIC code offset overflow (max 16 signed bits)")); - ex.X_op = O_constant; - macro_build ((char *) NULL, counter, &ex, - 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) + as_bad (_("PIC code offset overflow (max 16 signed bits)")); + ex.X_op = O_constant; + macro_build ((char *) NULL, counter, &ex, + HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", + "t,r,j", reg, reg, (int) BFD_RELOC_LO16); + } } } else if (mips_pic == EMBEDDED_PIC) @@ -4800,7 +4890,8 @@ macro (ip) && offset_expr.X_add_number < 0x8000) { macro_build ((char *) NULL, &icnt, &offset_expr, - (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu", + (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : + HAVE_NEWABI ? "addi" : "addiu", "t,r,j", treg, sreg, (int) BFD_RELOC_LO16); return; } @@ -4943,7 +5034,8 @@ macro (ip) && ! nopic_need_relax (offset_expr.X_add_symbol, 1)) { frag_grow (20); - macro_build ((char *) NULL, &icnt, &offset_expr, "addiu", + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_NEWABI ? "addi" : "addiu", "t,r,j", tempreg, mips_gp_register, (int) BFD_RELOC_GPREL16); p = frag_var (rs_machine_dependent, 8, 0, @@ -4954,11 +5046,12 @@ macro (ip) macro_build_lui (p, &icnt, &offset_expr, tempreg); if (p != NULL) p += 4; - macro_build (p, &icnt, &offset_expr, "addiu", + macro_build (p, &icnt, &offset_expr, + HAVE_NEWABI ? "addi" : "addiu", "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16); } } - else if (mips_pic == SVR4_PIC && ! mips_big_got) + else if (mips_pic == SVR4_PIC && ! mips_big_got && ! HAVE_NEWABI) { int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16; @@ -4990,13 +5083,6 @@ macro (ip) For a local symbol, we want the same instruction sequence, but we output a BFD_RELOC_LO16 reloc on the addiu instruction. - - For NewABI, we want for local or external data addresses - lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) - For a local function symbol, we want - lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) - nop - addiu $tempreg,$tempreg, (BFD_RELOC_MIPS_GOT_OFST) */ expr1.X_add_number = offset_expr.X_add_number; @@ -5004,8 +5090,6 @@ macro (ip) frag_grow (32); if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG) lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16; - else if (HAVE_NEWABI) - lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP; macro_build ((char *) NULL, &icnt, &offset_expr, HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", tempreg, lw_reloc_type, mips_gp_register); @@ -5099,7 +5183,137 @@ macro (ip) used_at = 1; } } - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC && ! mips_big_got && HAVE_NEWABI) + { + char *p = NULL; + int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP; + int adj = 0; + + /* If this is a reference to an external, and there is no + constant, or local symbol (*), with or without a + constant, we want + lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) + or if tempreg is PIC_CALL_REG + lw $tempreg,($gp) (BFD_RELOC_MIPS_CALL16) + + If we have a small constant, and this is a reference to + an external symbol, we want + lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) + addiu $tempreg,$tempreg, + + If we have a large constant, and this is a reference to + an external symbol, we want + lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) + lui $at, + addiu $at,$at, + addu $tempreg,$tempreg,$at + + (*) Other assemblers seem to prefer GOT_PAGE/GOT_OFST for + local symbols, even though it introduces an additional + instruction. */ + + frag_grow (28); + if (offset_expr.X_add_number == 0 && tempreg == PIC_CALL_REG) + lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16; + if (offset_expr.X_add_number) + { + frag_now->tc_frag_data.tc_fr_offset = + expr1.X_add_number = offset_expr.X_add_number; + offset_expr.X_add_number = 0; + + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, lw_reloc_type, + mips_gp_register); + + if (expr1.X_add_number >= -0x8000 + && expr1.X_add_number < 0x8000) + { + macro_build ((char *) NULL, &icnt, &expr1, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", tempreg, tempreg, + (int) BFD_RELOC_LO16); + p = frag_var (rs_machine_dependent, 4, 0, + RELAX_ENCODE (8, 4, 0, 0, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + } + else if (IS_SEXT_32BIT_NUM (expr1.X_add_number)) + { + int dreg; + + /* If we are going to add in a base register, and the + target register and the base register are the same, + then we are using AT as a temporary register. Since + we want to load the constant into AT, we add our + current AT (from the global offset table) and the + register into the register now, and pretend we were + not using a base register. */ + if (breg != treg) + dreg = tempreg; + else + { + assert (tempreg == AT); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", treg, AT, breg); + dreg = treg; + adj = 4; + } + + macro_build_lui ((char *) NULL, &icnt, &expr1, AT); + macro_build ((char *) NULL, &icnt, &expr1, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", AT, AT, (int) BFD_RELOC_LO16); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", dreg, dreg, AT); + + p = frag_var (rs_machine_dependent, 4 + adj, 0, + RELAX_ENCODE (16 + adj, 4 + adj, + 0, 0, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + + used_at = 1; + } + else + as_bad (_("PIC code offset overflow (max 32 signed bits)")); + + offset_expr.X_add_number = expr1.X_add_number; + + macro_build (p, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_DISP, + mips_gp_register); + if (adj) + { + macro_build (p + 4, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", treg, tempreg, breg); + breg = 0; + tempreg = treg; + } + } + else + { + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, lw_reloc_type, + mips_gp_register); + if (lw_reloc_type != BFD_RELOC_MIPS_GOT_DISP) + p = frag_var (rs_machine_dependent, 0, 0, + RELAX_ENCODE (0, 0, -4, 0, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + } + + if (! p) + { + /* To avoid confusion in tc_gen_reloc, we must ensure + that this does not become a variant frag. */ + frag_wane (frag_now); + frag_new (0); + } + } + else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI) { int gpdel; char *p; @@ -5146,10 +5360,7 @@ macro (ip) lui $at, addiu $at,$at, (BFD_RELOC_LO16) addu $tempreg,$tempreg,$at - - For NewABI, we want for local data addresses - lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_DISP) - */ + */ expr1.X_add_number = offset_expr.X_add_number; offset_expr.X_add_number = 0; @@ -5267,25 +5478,18 @@ macro (ip) if (gpdel > 0) { /* This is needed because this instruction uses $gp, but - the first instruction on the main stream does not. */ + the first instruction on the main stream does not. */ macro_build (p, &icnt, (expressionS *) NULL, "nop", ""); p += 4; } - if (HAVE_NEWABI) - local_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP; macro_build (p, &icnt, &offset_expr, HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", tempreg, local_reloc_type, mips_gp_register); p += 4; - if (expr1.X_add_number == 0 && HAVE_NEWABI) - { - /* BFD_RELOC_MIPS_GOT_DISP is sufficient for newabi */ - } - else - if (expr1.X_add_number >= -0x8000 + if (expr1.X_add_number >= -0x8000 && expr1.X_add_number < 0x8000) { macro_build (p, &icnt, (expressionS *) NULL, "nop", ""); @@ -5294,17 +5498,17 @@ macro (ip) HAVE_32BIT_ADDRESSES ? "addiu" : "daddiu", "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16); /* FIXME: If add_number is 0, and there was no base - register, the external symbol case ended with a load, - so if the symbol turns out to not be external, and - the next instruction uses tempreg, an unnecessary nop - will be inserted. */ + register, the external symbol case ended with a load, + so if the symbol turns out to not be external, and + the next instruction uses tempreg, an unnecessary nop + will be inserted. */ } else { if (breg == treg) { /* We must add in the base register now, as in the - external symbol case. */ + external symbol case. */ assert (tempreg == AT); macro_build (p, &icnt, (expressionS *) NULL, "nop", ""); p += 4; @@ -5314,7 +5518,7 @@ macro (ip) p += 4; tempreg = treg; /* We set breg to 0 because we have arranged to add - it in in both cases. */ + it in in both cases. */ breg = 0; } @@ -5330,6 +5534,146 @@ macro (ip) p += 4; } } + else if (mips_pic == SVR4_PIC && HAVE_NEWABI) + { + char *p = NULL; + int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16; + int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16; + int adj = 0; + + /* This is the large GOT case. If this is a reference to an + external symbol, and there is no constant, we want + lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) + add $tempreg,$tempreg,$gp + lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) + or if tempreg is PIC_CALL_REG + lui $tempreg, (BFD_RELOC_MIPS_CALL_HI16) + add $tempreg,$tempreg,$gp + lw $tempreg,($tempreg) (BFD_RELOC_MIPS_CALL_LO16) + + If we have a small constant, and this is a reference to + an external symbol, we want + lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) + add $tempreg,$tempreg,$gp + lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) + addi $tempreg,$tempreg, + + If we have a large constant, and this is a reference to + an external symbol, we want + lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) + addu $tempreg,$tempreg,$gp + lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) + lui $at, + addi $at,$at, + add $tempreg,$tempreg,$at + + If we have NewABI, and we know it's a local symbol, we want + lw $reg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) + addiu $reg,$reg, (BFD_RELOC_MIPS_GOT_OFST) + otherwise we have to resort to GOT_HI16/GOT_LO16. */ + + frag_grow (40); + + frag_now->tc_frag_data.tc_fr_offset = + expr1.X_add_number = offset_expr.X_add_number; + offset_expr.X_add_number = 0; + + if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG) + { + lui_reloc_type = (int) BFD_RELOC_MIPS_CALL_HI16; + lw_reloc_type = (int) BFD_RELOC_MIPS_CALL_LO16; + } + macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u", + tempreg, lui_reloc_type); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", tempreg, tempreg, mips_gp_register); + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, lw_reloc_type, tempreg); + + if (expr1.X_add_number == 0) + { + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (12, 8, 0, 4, 0, + mips_opts.warn_about_macros), + offset_expr.X_add_symbol, 0, NULL); + } + else if (expr1.X_add_number >= -0x8000 + && expr1.X_add_number < 0x8000) + { + macro_build ((char *) NULL, &icnt, &expr1, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", tempreg, tempreg, + (int) BFD_RELOC_LO16); + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (16, 8, 0, 4, 0, + mips_opts.warn_about_macros), + offset_expr.X_add_symbol, 0, NULL); + } + else if (IS_SEXT_32BIT_NUM (expr1.X_add_number)) + { + int dreg; + + /* If we are going to add in a base register, and the + target register and the base register are the same, + then we are using AT as a temporary register. Since + we want to load the constant into AT, we add our + current AT (from the global offset table) and the + register into the register now, and pretend we were + not using a base register. */ + if (breg != treg) + dreg = tempreg; + else + { + assert (tempreg == AT); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", treg, AT, breg); + dreg = treg; + adj = 4; + } + + /* Set mips_optimize around the lui instruction to avoid + inserting an unnecessary nop after the lw. */ + macro_build_lui ((char *) NULL, &icnt, &expr1, AT); + macro_build ((char *) NULL, &icnt, &expr1, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", AT, AT, (int) BFD_RELOC_LO16); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", dreg, dreg, AT); + + p = frag_var (rs_machine_dependent, 8 + adj, 0, + RELAX_ENCODE (24 + adj, 8 + adj, + 0, 4, 0, + (breg == 0 + ? mips_opts.warn_about_macros + : 0)), + offset_expr.X_add_symbol, 0, NULL); + + used_at = 1; + } + else + as_bad (_("PIC code offset overflow (max 32 signed bits)")); + + offset_expr.X_add_number = expr1.X_add_number; + macro_build (p, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", + tempreg, + (int) BFD_RELOC_MIPS_GOT_PAGE, mips_gp_register); + macro_build (p + 4, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", "t,r,j", + tempreg, tempreg, (int) BFD_RELOC_MIPS_GOT_OFST); + if (adj) + { + macro_build (p + 8, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", treg, tempreg, breg); + breg = 0; + tempreg = treg; + } + } else if (mips_pic == EMBEDDED_PIC) { /* We use @@ -5347,9 +5691,10 @@ macro (ip) char *s; if (mips_pic == EMBEDDED_PIC || mips_pic == NO_PIC) - s = (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : "addu"; + s = (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : + HAVE_NEWABI ? "add" : "addu"; else - s = HAVE_64BIT_ADDRESSES ? "daddu" : "addu"; + s = HAVE_64BIT_ADDRESSES ? "daddu" : HAVE_NEWABI ? "add" : "addu"; macro_build ((char *) NULL, &icnt, (expressionS *) NULL, s, "d,v,t", treg, tempreg, breg); @@ -5448,16 +5793,52 @@ macro (ip) jalr $ra,$25 nop lw $gp,cprestore($sp) - For NewABI, we want - lw $25,($gp) (BFD_RELOC_MIPS_GOT_DISP) - jalr $ra,$25 (BFD_RELOC_MIPS_JALR) - */ + + For NewABI, we use the same CALL16 or CALL_HI16/CALL_LO16 + sequences above, minus nops, unless the symbol is local, + which enables us to use GOT_PAGE/GOT_OFST (big got) or + GOT_DISP. */ 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_GOT_DISP, mips_gp_register); + if (! mips_big_got) + { + frag_grow (4); + 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); + frag_var (rs_machine_dependent, 0, 0, + RELAX_ENCODE (0, 0, -4, 0, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + } + else + { + frag_grow (20); + 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 ? "add" : "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); + p = frag_var (rs_machine_dependent, 8, 0, + RELAX_ENCODE (12, 8, 0, 4, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + macro_build (p, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", "t,o(b)", + tempreg, (int) BFD_RELOC_MIPS_GOT_PAGE, + mips_gp_register); + macro_build (p + 4, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "addi" : "daddiu", + "t,r,j", tempreg, tempreg, + (int) BFD_RELOC_MIPS_GOT_OFST); + } + macro_build_jalr (icnt, &offset_expr); } else @@ -5762,7 +6143,7 @@ macro (ip) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, ((bfd_arch_bits_per_address (stdoutput) == 32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) - ? "addu" : "daddu"), + ? HAVE_NEWABI ? "add" : "addu" : "daddu"), "d,v,t", tempreg, tempreg, breg); macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt, treg, (int) BFD_RELOC_PCREL_LO16, tempreg); @@ -5952,7 +6333,8 @@ macro (ip) { frag_grow (28); macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", tempreg, breg, mips_gp_register); macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt, treg, (int) BFD_RELOC_GPREL16, tempreg); @@ -5964,7 +6346,8 @@ macro (ip) if (p != NULL) p += 4; macro_build (p, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", tempreg, tempreg, breg); if (p != NULL) p += 4; @@ -5986,8 +6369,11 @@ macro (ip) nop addiu $tempreg,$tempreg, (BFD_RELOC_LO16) $treg,0($tempreg) - If we have NewABI, we want - lw $reg,($gp) (BFD_RELOC_MIPS_GOT_DISP) + + For NewABI, we want + lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) + $treg,($tempreg) (BFD_RELOC_MIPS_GOT_OFST) + If there is a base register, we add it to $tempreg before the . If there is a constant, we stick it in the instruction. We don't handle constants larger than @@ -5995,10 +6381,26 @@ macro (ip) (actually, we could handle them for the subset of cases in which we are not using $at). */ assert (offset_expr.X_op == O_symbol); + 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); + if (breg != 0) + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", tempreg, tempreg, breg); + macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt, treg, + (int) BFD_RELOC_MIPS_GOT_OFST, tempreg); + + if (! used_at) + return; + + break; + } expr1.X_add_number = offset_expr.X_add_number; offset_expr.X_add_number = 0; - if (HAVE_NEWABI) - lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_DISP; if (expr1.X_add_number < -0x8000 || expr1.X_add_number >= 0x8000) as_bad (_("PIC code offset overflow (max 16 signed bits)")); @@ -6020,7 +6422,7 @@ macro (ip) macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg, (int) BFD_RELOC_LO16, tempreg); } - else if (mips_pic == SVR4_PIC) + else if (mips_pic == SVR4_PIC && ! HAVE_NEWABI) { int gpdel; char *p; @@ -6040,41 +6442,13 @@ 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). - - For NewABI, we want - lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) - addiu $tempreg,$tempreg, (BFD_RELOC_MIPS_GOT_OFST) - $treg,0($tempreg) - */ + in which we are not using $at). */ 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 @@ -6114,6 +6488,60 @@ macro (ip) macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg, (int) BFD_RELOC_LO16, tempreg); } + else if (mips_pic == SVR4_PIC && HAVE_NEWABI) + { + char *p; + int bregsz = breg != 0 ? 4 : 0; + + /* If this is a reference to an external symbol, we want + lui $tempreg, (BFD_RELOC_MIPS_GOT_HI16) + add $tempreg,$tempreg,$gp + lw $tempreg,($tempreg) (BFD_RELOC_MIPS_GOT_LO16) + $treg,($tempreg) + Otherwise, for local symbols, we want: + lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT_PAGE) + $treg,($tempreg) (BFD_RELOC_MIPS_GOT_OFST) */ + assert (offset_expr.X_op == O_symbol); + frag_now->tc_frag_data.tc_fr_offset = + 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)")); + frag_grow (36); + macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u", + tempreg, (int) BFD_RELOC_MIPS_GOT_HI16); + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", tempreg, tempreg, mips_gp_register); + macro_build ((char *) NULL, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16, + tempreg); + if (breg != 0) + macro_build ((char *) NULL, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", tempreg, tempreg, breg); + macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg, + (int) BFD_RELOC_LO16, tempreg); + + offset_expr.X_add_number = expr1.X_add_number; + p = frag_var (rs_machine_dependent, 12 + bregsz, 0, + RELAX_ENCODE (16 + bregsz, 8 + bregsz, + 0, 4 + bregsz, 0, 0), + offset_expr.X_add_symbol, 0, NULL); + macro_build (p, &icnt, &offset_expr, + HAVE_32BIT_ADDRESSES ? "lw" : "ld", + "t,o(b)", tempreg, + (int) BFD_RELOC_MIPS_GOT_PAGE, + mips_gp_register); + if (breg != 0) + macro_build (p + 4, &icnt, (expressionS *) NULL, + HAVE_32BIT_ADDRESSES ? "add" : "daddu", + "d,v,t", tempreg, tempreg, breg); + macro_build (p + 4 + bregsz, &icnt, &offset_expr, s, fmt, treg, + (int) BFD_RELOC_MIPS_GOT_OFST, tempreg); + } else if (mips_pic == EMBEDDED_PIC) { /* If there is no base register, we want @@ -6505,7 +6933,8 @@ macro (ip) { frag_grow (36); macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, breg, mips_gp_register); tempreg = AT; off = 4; @@ -6560,7 +6989,8 @@ macro (ip) if (breg != 0) { macro_build (p, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, breg, AT); if (p != NULL) p += 4; @@ -6612,7 +7042,8 @@ macro (ip) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", ""); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, breg, AT); /* Itbl support may require additional care here. */ macro_build ((char *) NULL, &icnt, &expr1, s, fmt, @@ -6672,7 +7103,8 @@ macro (ip) macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u", AT, (int) BFD_RELOC_MIPS_GOT_HI16); macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, AT, mips_gp_register); macro_build ((char *) NULL, &icnt, &offset_expr, HAVE_32BIT_ADDRESSES ? "lw" : "ld", @@ -6680,7 +7112,8 @@ macro (ip) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "nop", ""); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, breg, AT); /* Itbl support may require additional care here. */ macro_build ((char *) NULL, &icnt, &expr1, s, fmt, @@ -6718,7 +7151,8 @@ macro (ip) if (breg != 0) { macro_build (p, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, breg, AT); p += 4; } @@ -7643,7 +8077,8 @@ macro2 (ip) load_address (&icnt, AT, &offset_expr, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, AT, breg); if (! target_big_endian) expr1.X_add_number = off; @@ -7665,7 +8100,8 @@ macro2 (ip) load_address (&icnt, AT, &offset_expr, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, AT, breg); if (target_big_endian) expr1.X_add_number = 0; @@ -7739,7 +8175,8 @@ macro2 (ip) load_address (&icnt, AT, &offset_expr, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, AT, breg); if (! target_big_endian) expr1.X_add_number = off; @@ -7760,7 +8197,8 @@ macro2 (ip) load_address (&icnt, AT, &offset_expr, &used_at); if (breg != 0) macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI + ? "add" : "addu" : "daddu", "d,v,t", AT, AT, breg); if (! target_big_endian) expr1.X_add_number = 0; @@ -12359,7 +12797,7 @@ s_cpsetup (ignore) 0, NULL, 0, 0, BFD_RELOC_LO16); macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_64BIT_ADDRESSES ? "daddu" : "addu", "d,v,t", + HAVE_64BIT_ADDRESSES ? "daddu" : "add", "d,v,t", mips_gp_register, mips_gp_register, reg1); demand_empty_rest_of_line (); @@ -12578,7 +13016,7 @@ s_cpadd (ignore) /* Add $gp to the register named as an argument. */ reg = tc_get_register (0); macro_build ((char *) NULL, &icnt, (expressionS *) NULL, - HAVE_32BIT_ADDRESSES ? "addu" : "daddu", + HAVE_32BIT_ADDRESSES ? HAVE_NEWABI ? "add" : "addu" : "daddu", "d,v,t", reg, reg, mips_gp_register); demand_empty_rest_of_line (); @@ -13336,6 +13774,8 @@ tc_gen_reloc (section, fixp) if (fixp->fx_frag->fr_opcode != NULL && ((fixp->fx_r_type == BFD_RELOC_GPREL16 && ! HAVE_NEWABI) + || (fixp->fx_r_type == BFD_RELOC_MIPS_GOT_DISP + && HAVE_NEWABI) || fixp->fx_r_type == BFD_RELOC_MIPS_GOT16 || fixp->fx_r_type == BFD_RELOC_MIPS_CALL16 || fixp->fx_r_type == BFD_RELOC_MIPS_GOT_HI16 @@ -13369,6 +13809,7 @@ tc_gen_reloc (section, fixp) fixp->fx_where = fixp->fx_frag->fr_opcode - fixp->fx_frag->fr_literal; reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + reloc->addend += fixp->fx_frag->tc_frag_data.tc_fr_offset; reloc2 = retval[1] = (arelent *) xmalloc (sizeof (arelent)); retval[2] = NULL; reloc2->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); @@ -13376,7 +13817,8 @@ tc_gen_reloc (section, fixp) reloc2->address = (reloc->address + (RELAX_RELOC2 (fixp->fx_frag->fr_subtype) - RELAX_RELOC1 (fixp->fx_frag->fr_subtype))); - reloc2->addend = fixp->fx_addnumber; + reloc2->addend = fixp->fx_addnumber + + fixp->fx_frag->tc_frag_data.tc_fr_offset; reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_LO16); assert (reloc2->howto != NULL); @@ -13405,12 +13847,8 @@ tc_gen_reloc (section, fixp) break; case BFD_RELOC_MIPS_GOT_LO16: case BFD_RELOC_MIPS_CALL_LO16: - fixp->fx_r_type = BFD_RELOC_MIPS_GOT16; - break; - case BFD_RELOC_MIPS_CALL16: if (HAVE_NEWABI) { - /* BFD_RELOC_MIPS_GOT16;*/ fixp->fx_r_type = BFD_RELOC_MIPS_GOT_PAGE; reloc2->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_MIPS_GOT_OFST); @@ -13418,17 +13856,26 @@ tc_gen_reloc (section, fixp) else fixp->fx_r_type = BFD_RELOC_MIPS_GOT16; break; + case BFD_RELOC_MIPS_CALL16: + case BFD_RELOC_MIPS_GOT_OFST: + case BFD_RELOC_MIPS_GOT_DISP: + if (HAVE_NEWABI) + { + /* It may seem nonsensical to relax GOT_DISP to + GOT_DISP, but we're actually turning a GOT_DISP + without offset into a GOT_DISP with an offset, + getting rid of the separate addition, which we can + do when the symbol is found to be local. */ + fixp->fx_r_type = BFD_RELOC_MIPS_GOT_DISP; + retval[1] = NULL; + } + else + fixp->fx_r_type = BFD_RELOC_MIPS_GOT16; + break; } } else abort (); - - /* newabi uses R_MIPS_GOT_DISP for local symbols */ - if (HAVE_NEWABI && fixp->fx_r_type == BFD_RELOC_MIPS_GOT_LO16) - { - fixp->fx_r_type = BFD_RELOC_MIPS_GOT_DISP; - retval[1] = NULL; - } } /* Since the old MIPS ELF ABI uses Rel instead of Rela, encode the vtable @@ -13867,7 +14314,7 @@ md_convert_frag (abfd, asec, fragp) fixptr = fragp->fr_literal + fragp->fr_fix; if (new > 0) - memcpy (fixptr - old, fixptr, new); + memmove (fixptr - old, fixptr, new); fragp->fr_fix += new - old; } diff --git a/gas/config/tc-mips.h b/gas/config/tc-mips.h index b3c2d01..17993b9 100644 --- a/gas/config/tc-mips.h +++ b/gas/config/tc-mips.h @@ -193,4 +193,9 @@ extern enum dwarf2_format mips_dwarf2_format PARAMS ((void)); #define DWARF2_ADDR_SIZE(bfd) \ (DWARF2_FORMAT () == dwarf2_format_32bit ? 4 : 8) +typedef struct { + offsetT tc_fr_offset; +} tc_frag_data_type; +#define TC_FRAG_TYPE tc_frag_data_type + #endif /* TC_MIPS */ -- cgit v1.1