* config/tc-mips.c (enum mips_pic_level): New enum.

(mips_pic): Change from int to enum mips_pic_level.  Change all
	uses (0 becomes NO_PIC, 2 becomes SVR4_PIC).
	(load_address): Handle EMBEDDED_PIC.
	(macro): Handle EMBEDDED_PIC in all PIC cases.
	(md_parse_option): Accept -membedded-pic to use EMBEDDED_PIC.  If
	OBJ_ELF, accept -KPIC and -call_shared to use SVR4_PIC and accept
	-non_shared to use NO_PIC (this is how the Irix 5 assembler
	works).  Do not permit -G with SVR4_PIC.
	(s_abicalls): Warn if -G was used, and force -G 0.
	(tc_gen_reloc): Set reloc->addend to 0 for a PC relative reloc for
	anything but a.out, not just for ELF.  For ECOFF, don't generate a
	BFD_RELOC_16_PCREL_S2 reloc unless using EMBEDDED_PIC.
This commit is contained in:
Ian Lance Taylor
1994-03-22 20:27:58 +00:00
parent c031ba0b95
commit d9aba8051e
2 changed files with 339 additions and 123 deletions

View File

@ -1,5 +1,19 @@
Tue Mar 22 13:58:37 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) Tue Mar 22 13:58:37 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
* config/tc-mips.c (enum mips_pic_level): New enum.
(mips_pic): Change from int to enum mips_pic_level. Change all
uses (0 becomes NO_PIC, 2 becomes SVR4_PIC).
(load_address): Handle EMBEDDED_PIC.
(macro): Handle EMBEDDED_PIC in all PIC cases.
(md_parse_option): Accept -membedded-pic to use EMBEDDED_PIC. If
OBJ_ELF, accept -KPIC and -call_shared to use SVR4_PIC and accept
-non_shared to use NO_PIC (this is how the Irix 5 assembler
works). Do not permit -G with SVR4_PIC.
(s_abicalls): Warn if -G was used, and force -G 0.
(tc_gen_reloc): Set reloc->addend to 0 for a PC relative reloc for
anything but a.out, not just for ELF. For ECOFF, don't generate a
BFD_RELOC_16_PCREL_S2 reloc unless using EMBEDDED_PIC.
* config/obj-ecoff.h (obj_sec_sym_ok_for_reloc): Define to be 1. * config/obj-ecoff.h (obj_sec_sym_ok_for_reloc): Define to be 1.
Sun Mar 20 16:31:55 1994 Jeffrey A. Law (law@snake.cs.utah.edu) Sun Mar 20 16:31:55 1994 Jeffrey A. Law (law@snake.cs.utah.edu)

View File

@ -103,9 +103,28 @@ static int mips_isa = -1;
/* MIPS ISA we are using for this output file. */ /* MIPS ISA we are using for this output file. */
static int file_mips_isa; static int file_mips_isa;
/* MIPS PIC level. 0 is normal, non-PIC code. 2 means to generate /* MIPS PIC level. */
SVR4 ABI PIC calls. 1 doesn't mean anything. */
static int mips_pic; enum mips_pic_level
{
/* Do not generate PIC code. */
NO_PIC,
/* Generate PIC code as in Irix 4. This is not implemented, and I'm
not sure what it is supposed to do. */
IRIX4_PIC,
/* Generate PIC code as in the SVR4 MIPS ABI. */
SVR4_PIC,
/* Generate PIC code without using a global offset table: the data
segment has a maximum size of 64K, all data references are off
the $gp register, and all text references are PC relative. This
is used on some embedded systems. */
EMBEDDED_PIC
};
static enum mips_pic_level mips_pic;
/* 1 if trap instructions should used for overflow rather than break /* 1 if trap instructions should used for overflow rather than break
instructions. */ instructions. */
@ -1406,7 +1425,7 @@ macro_build_lui (place, counter, ep, regnum)
{ {
assert (ep->X_op == O_symbol); assert (ep->X_op == O_symbol);
/* _gp_disp is a special case, used from s_cpload. */ /* _gp_disp is a special case, used from s_cpload. */
assert (mips_pic == 0 assert (mips_pic == NO_PIC
|| strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0); || strcmp (S_GET_NAME (ep->X_add_symbol), "_gp_disp") == 0);
r = BFD_RELOC_HI16_S; r = BFD_RELOC_HI16_S;
} }
@ -1558,8 +1577,12 @@ load_address (counter, reg, ep)
} }
if (ep->X_op == O_constant) if (ep->X_op == O_constant)
load_register (counter, reg, ep); {
else if (mips_pic == 0) load_register (counter, reg, ep);
return;
}
if (mips_pic == NO_PIC)
{ {
/* If this is a reference to a GP relative symbol, we want /* If this is a reference to a GP relative symbol, we want
addiu $reg,$gp,<sym> (BFD_RELOC_MIPS_GPREL) addiu $reg,$gp,<sym> (BFD_RELOC_MIPS_GPREL)
@ -1586,7 +1609,7 @@ load_address (counter, reg, ep)
mips_isa < 3 ? "addiu" : "daddiu", mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", reg, reg, (int) BFD_RELOC_LO16); "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
} }
else else if (mips_pic == SVR4_PIC)
{ {
expressionS ex; expressionS ex;
@ -1596,7 +1619,7 @@ load_address (counter, reg, ep)
lw $reg,<sym>($gp) (BFD_RELOC_MIPS_GOT16) lw $reg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop nop
addiu $reg,$reg,<sym> (BFD_RELOC_LO16) addiu $reg,$reg,<sym> (BFD_RELOC_LO16)
If there is a constant, it must be added in afterward. */ If there is a constant, it must be added in after. */
ex.X_add_number = ep->X_add_number; ex.X_add_number = ep->X_add_number;
ep->X_add_number = 0; ep->X_add_number = 0;
frag_grow (20); frag_grow (20);
@ -1619,7 +1642,18 @@ load_address (counter, reg, ep)
mips_isa < 3 ? "addiu" : "daddiu", mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", reg, reg, (int) BFD_RELOC_LO16); "t,r,j", reg, reg, (int) BFD_RELOC_LO16);
} }
} }
else if (mips_pic == EMBEDDED_PIC)
{
/* We always do
addiu $reg,$gp,<sym> (BFD_RELOC_MIPS_GPREL)
*/
macro_build ((char *) NULL, counter, ep,
mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", reg, GP, (int) BFD_RELOC_MIPS_GPREL);
}
else
abort ();
} }
/* /*
@ -2292,8 +2326,8 @@ macro (ip)
return; return;
case M_LA_AB: case M_LA_AB:
/* Load the address of a symbol into a register. If M_LA_AB, we /* Load the address of a symbol into a register. If breg is not
then add a base register to it. */ zero, we then add a base register to it. */
if (offset_expr.X_op != O_symbol if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant) && offset_expr.X_op != O_constant)
{ {
@ -2314,7 +2348,7 @@ macro (ip)
if (offset_expr.X_op == O_constant) if (offset_expr.X_op == O_constant)
load_register (&icnt, tempreg, &offset_expr); load_register (&icnt, tempreg, &offset_expr);
else if (mips_pic == 0) else if (mips_pic == NO_PIC)
{ {
/* If this is a reference to an GP relative symbol, we want /* If this is a reference to an GP relative symbol, we want
addiu $tempreg,$gp,<sym> (BFD_RELOC_MIPS_GPREL) addiu $tempreg,$gp,<sym> (BFD_RELOC_MIPS_GPREL)
@ -2344,7 +2378,7 @@ macro (ip)
mips_isa < 3 ? "addiu" : "daddiu", mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16); "t,r,j", tempreg, tempreg, (int) BFD_RELOC_LO16);
} }
else else if (mips_pic == SVR4_PIC)
{ {
/* If this is a reference to an external symbol, and there /* If this is a reference to an external symbol, and there
is no constant, we want is no constant, we want
@ -2464,6 +2498,17 @@ macro (ip)
used_at = 1; used_at = 1;
} }
} }
else if (mips_pic == EMBEDDED_PIC)
{
/* We use
addiu $tempreg,$gp,<sym> (BFD_RELOC_MIPS_GPREL)
*/
macro_build ((char *) NULL, &icnt, &offset_expr,
mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", tempreg, GP, (int) BFD_RELOC_MIPS_GPREL);
}
else
abort ();
if (breg != 0) if (breg != 0)
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
@ -2479,7 +2524,7 @@ macro (ip)
/* The j instruction may not be used in PIC code, since it /* The j instruction may not be used in PIC code, since it
requires an absolute address. We convert it to a b requires an absolute address. We convert it to a b
instruction. */ instruction. */
if (mips_pic == 0) if (mips_pic == NO_PIC)
macro_build ((char *) NULL, &icnt, &offset_expr, "j", "a"); macro_build ((char *) NULL, &icnt, &offset_expr, "j", "a");
else else
macro_build ((char *) NULL, &icnt, &offset_expr, "b", "p"); macro_build ((char *) NULL, &icnt, &offset_expr, "b", "p");
@ -2492,83 +2537,86 @@ macro (ip)
dreg = RA; dreg = RA;
/* Fall through. */ /* Fall through. */
case M_JAL_2: case M_JAL_2:
if (mips_pic == 0) if (mips_pic == NO_PIC
|| mips_pic == EMBEDDED_PIC)
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
"d,s", dreg, sreg);
else if (mips_pic == SVR4_PIC)
{ {
if (sreg != PIC_CALL_REG)
as_warn ("MIPS PIC call to register other than $25");
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr",
"d,s", dreg, sreg); "d,s", dreg, sreg);
return; if (mips_cprestore_offset < 0)
as_warn ("No .cprestore pseudo-op used in PIC code");
else
{
expr1.X_add_number = mips_cprestore_offset;
macro_build ((char *) NULL, &icnt, &expr1,
mips_isa < 3 ? "lw" : "ld",
"t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
}
} }
/* I only know how to handle pic2. */
assert (mips_pic == 2);
if (sreg != PIC_CALL_REG)
as_warn ("MIPS PIC call to register other than $25");
macro_build ((char *) NULL, &icnt, (expressionS *) NULL, "jalr", "d,s",
dreg, sreg);
if (mips_cprestore_offset < 0)
as_warn ("No .cprestore pseudo-op used in PIC code");
else else
{ abort ();
expr1.X_add_number = mips_cprestore_offset;
macro_build ((char *) NULL, &icnt, &expr1,
mips_isa < 3 ? "lw" : "ld",
"t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg);
}
return; return;
case M_JAL_A: case M_JAL_A:
if (mips_pic == 0) if (mips_pic == NO_PIC)
macro_build ((char *) NULL, &icnt, &offset_expr, "jal", "a");
else if (mips_pic == SVR4_PIC)
{ {
macro_build ((char *) NULL, &icnt, &offset_expr, "jal", "a"); /* If this is a reference to an external symbol, we want
return; lw $25,<sym>($gp) (BFD_RELOC_MIPS_CALL16)
} nop
jalr $25
/* I only know how to handle pic2. */ nop
assert (mips_pic == 2); lw $gp,cprestore($sp)
The cprestore value is set using the .cprestore
/* If this is a reference to an external symbol, we want pseudo-op. If the symbol is not external, we want
lw $25,<sym>($gp) (BFD_RELOC_MIPS_CALL16) lw $25,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
nop nop
jalr $25 addiu $25,$25,<sym> (BFD_RELOC_LO16)
nop jalr $25
lw $gp,cprestore($sp) nop
The cprestore value is set using the .cprestore pseudo-op. lw $gp,cprestore($sp)
If the symbol is not external, we want */
lw $25,<sym>($gp) (BFD_RELOC_MIPS_GOT16) frag_grow (20);
nop macro_build ((char *) NULL, &icnt, &offset_expr,
addiu $25,$25,<sym> (BFD_RELOC_LO16)
jalr $25
nop
lw $gp,cprestore($sp)
*/
frag_grow (20);
macro_build ((char *) NULL, &icnt, &offset_expr,
mips_isa < 3 ? "lw" : "ld",
"t,o(b)", PIC_CALL_REG, (int) BFD_RELOC_MIPS_CALL16, GP);
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, (long) 0, (char *) NULL);
macro_build (p, &icnt, &offset_expr,
mips_isa < 3 ? "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 (mips_cprestore_offset < 0)
as_warn ("No .cprestore pseudo-op used in PIC code");
else
{
if (mips_noreorder)
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
"nop", "");
expr1.X_add_number = mips_cprestore_offset;
macro_build ((char *) NULL, &icnt, &expr1,
mips_isa < 3 ? "lw" : "ld", mips_isa < 3 ? "lw" : "ld",
"t,o(b)", GP, (int) BFD_RELOC_LO16, mips_frame_reg); "t,o(b)", PIC_CALL_REG,
(int) BFD_RELOC_MIPS_CALL16, GP);
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, (long) 0, (char *) NULL);
macro_build (p, &icnt, &offset_expr,
mips_isa < 3 ? "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 (mips_cprestore_offset < 0)
as_warn ("No .cprestore pseudo-op used in PIC code");
else
{
if (mips_noreorder)
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
"nop", "");
expr1.X_add_number = mips_cprestore_offset;
macro_build ((char *) NULL, &icnt, &expr1,
mips_isa < 3 ? "lw" : "ld",
"t,o(b)", GP, (int) BFD_RELOC_LO16,
mips_frame_reg);
}
} }
else if (mips_pic == EMBEDDED_PIC)
macro_build ((char *) NULL, &icnt, &offset_expr, "bal", "p");
else
abort ();
return; return;
case M_LB_AB: case M_LB_AB:
@ -2725,13 +2773,13 @@ macro (ip)
/* A constant expression in PIC code can be handled just as it /* A constant expression in PIC code can be handled just as it
is in non PIC code. */ is in non PIC code. */
if (mips_pic == 0 if (mips_pic == NO_PIC
|| offset_expr.X_op == O_constant) || offset_expr.X_op == O_constant)
{ {
/* If this is a reference to a GP relative symbol, and there /* If this is a reference to a GP relative symbol, and there
is no base register, we want is no base register, we want
<op> $treg,<sym>($gp) (BFD_RELOC_MIPS_GPREL) <op> $treg,<sym>($gp) (BFD_RELOC_MIPS_GPREL)
Otherwise we want Otherwise, if there is no base register, we want
lui $tempreg,<sym> (BFD_RELOC_HI16_S) lui $tempreg,<sym> (BFD_RELOC_HI16_S)
<op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16)
If we have a constant, we need two instructions anyhow, If we have a constant, we need two instructions anyhow,
@ -2798,7 +2846,7 @@ macro (ip)
(int) BFD_RELOC_LO16, tempreg); (int) BFD_RELOC_LO16, tempreg);
} }
} }
else else if (mips_pic == SVR4_PIC)
{ {
/* If this is a reference to an external symbol, we want /* If this is a reference to an external symbol, we want
lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16) lw $tempreg,<sym>($gp) (BFD_RELOC_MIPS_GOT16)
@ -2840,6 +2888,32 @@ macro (ip)
macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg, macro_build ((char *) NULL, &icnt, &expr1, s, fmt, treg,
(int) BFD_RELOC_LO16, tempreg); (int) BFD_RELOC_LO16, tempreg);
} }
else if (mips_pic == EMBEDDED_PIC)
{
/* If there is no base register, we want
<op> $treg,<sym>($gp) (BFD_RELOC_MIPS_GPREL)
If there is a base register, we want
addu $tempreg,$breg,$gp
<op> $treg,<sym>($tempreg) (BFD_RELOC_MIPS_GPREL)
*/
assert (offset_expr.X_op == O_symbol);
if (breg == 0)
{
macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
treg, (int) BFD_RELOC_MIPS_GPREL, GP);
used_at = 0;
}
else
{
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
mips_isa < 3 ? "addu" : "daddu",
"d,v,t", tempreg, breg, GP);
macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
treg, (int) BFD_RELOC_MIPS_GPREL, tempreg);
}
}
else
abort ();
if (! used_at) if (! used_at)
return; return;
@ -2852,7 +2926,7 @@ macro (ip)
return; return;
case M_LI_SS: case M_LI_SS:
if (mips_pic == 0) if (mips_pic == NO_PIC)
{ {
assert (offset_expr.X_op == O_symbol assert (offset_expr.X_op == O_symbol
&& strcmp (segment_name (S_GET_SEGMENT && strcmp (segment_name (S_GET_SEGMENT
@ -2862,27 +2936,44 @@ macro (ip)
macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)", macro_build ((char *) NULL, &icnt, &offset_expr, "lwc1", "T,o(b)",
treg, (int) BFD_RELOC_MIPS_LITERAL, GP); treg, (int) BFD_RELOC_MIPS_LITERAL, GP);
} }
else else if (mips_pic == SVR4_PIC
|| mips_pic == EMBEDDED_PIC)
{ {
assert (imm_expr.X_op == O_constant); assert (imm_expr.X_op == O_constant);
load_register (&icnt, treg, &imm_expr); load_register (&icnt, treg, &imm_expr);
} }
else
abort ();
return; return;
case M_LI_D: case M_LI_D:
/* We know that sym is in the .rdata instruction. First we get /* We know that sym is in the .rdata section. First we get the
the upper 16 bits of the address. */ upper 16 bits of the address. */
if (mips_pic == 0) if (mips_pic == NO_PIC)
{ {
/* FIXME: This won't work for a 64 bit address. */ /* FIXME: This won't work for a 64 bit address. */
macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT); macro_build_lui ((char *) NULL, &icnt, &offset_expr, AT);
} }
else else if (mips_pic == SVR4_PIC)
{ {
macro_build ((char *) NULL, &icnt, &offset_expr, macro_build ((char *) NULL, &icnt, &offset_expr,
mips_isa < 3 ? "lw" : "ld", mips_isa < 3 ? "lw" : "ld",
"t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP); "t,o(b)", AT, (int) BFD_RELOC_MIPS_GOT16, GP);
} }
else if (mips_pic == EMBEDDED_PIC)
{
/* For embedded PIC we pick up the entire address off $gp in
a single instruction. */
macro_build ((char *) NULL, &icnt, &offset_expr,
mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", AT, GP, (int) BFD_RELOC_MIPS_GPREL);
offset_expr.X_op = O_constant;
offset_expr.X_add_number = 0;
}
else
abort ();
/* Now we load the register(s). */ /* Now we load the register(s). */
if (mips_isa >= 3) if (mips_isa >= 3)
macro_build ((char *) NULL, &icnt, &offset_expr, "ld", "t,o(b)", macro_build ((char *) NULL, &icnt, &offset_expr, "ld", "t,o(b)",
@ -2904,7 +2995,8 @@ macro (ip)
break; break;
case M_LI_DD: case M_LI_DD:
if (mips_pic == 0) if (mips_pic == NO_PIC
|| mips_pic == EMBEDDED_PIC)
{ {
/* Load a floating point number from the .lit8 section. */ /* Load a floating point number from the .lit8 section. */
assert (offset_expr.X_op == O_symbol assert (offset_expr.X_op == O_symbol
@ -2922,7 +3014,7 @@ macro (ip)
r = BFD_RELOC_MIPS_LITERAL; r = BFD_RELOC_MIPS_LITERAL;
goto dob; goto dob;
} }
else else if (mips_pic == SVR4_PIC)
{ {
/* Load the double from the .rdata section. */ /* Load the double from the .rdata section. */
macro_build ((char *) NULL, &icnt, &offset_expr, macro_build ((char *) NULL, &icnt, &offset_expr,
@ -2938,6 +3030,8 @@ macro (ip)
r = BFD_RELOC_LO16; r = BFD_RELOC_LO16;
goto dob; goto dob;
} }
else
abort ();
case M_L_DOB: case M_L_DOB:
/* Even on a big endian machine $fn comes before $fn+1. We have /* Even on a big endian machine $fn comes before $fn+1. We have
@ -3028,7 +3122,7 @@ macro (ip)
if (byte_order == LITTLE_ENDIAN) if (byte_order == LITTLE_ENDIAN)
coproc = 0; coproc = 0;
if (mips_pic == 0 if (mips_pic == NO_PIC
|| offset_expr.X_op == O_constant) || offset_expr.X_op == O_constant)
{ {
/* If this is a reference to a GP relative symbol, we want /* If this is a reference to a GP relative symbol, we want
@ -3118,7 +3212,7 @@ macro (ip)
coproc ? treg : treg + 1, coproc ? treg : treg + 1,
(int) BFD_RELOC_LO16, AT); (int) BFD_RELOC_LO16, AT);
} }
else else if (mips_pic == SVR4_PIC)
{ {
int off; int off;
@ -3166,6 +3260,40 @@ macro (ip)
offset_expr.X_add_symbol, (long) 0, offset_expr.X_add_symbol, (long) 0,
(char *) NULL); (char *) NULL);
} }
else if (mips_pic == EMBEDDED_PIC)
{
/* If there is no base register, we use
<op> $treg,<sym>($gp) (BFD_RELOC_MIPS_GPREL)
<op> $treg+1,<sym>+4($gp) (BFD_RELOC_MIPS_GPREL)
If we have a base register, we use
addu $at,$breg,$gp
<op> $treg,<sym>($at) (BFD_RELOC_MIPS_GPREL)
<op> $treg+1,<sym>+4($at) (BFD_RELOC_MIPS_GPREL)
*/
if (breg == 0)
{
tempreg = GP;
used_at = 0;
}
else
{
macro_build ((char *) NULL, &icnt, (expressionS *) NULL,
mips_isa < 3 ? "addu" : "daddu",
"d,v,t", AT, breg, GP);
tempreg = AT;
used_at = 1;
}
macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
coproc ? treg + 1 : treg,
(int) BFD_RELOC_MIPS_GPREL, tempreg);
offset_expr.X_add_number += 4;
macro_build ((char *) NULL, &icnt, &offset_expr, s, fmt,
coproc ? treg : treg + 1,
(int) BFD_RELOC_MIPS_GPREL, tempreg);
}
else
abort ();
if (! used_at) if (! used_at)
return; return;
@ -4242,9 +4370,15 @@ mips_ip (str, ip)
f -- immediate value f -- immediate value
l -- .lit4 l -- .lit4
When generating PIC code, we do not use the .lit8 When generating SVR4 PIC code, we do not use the
or .lit4 sections at all, in order to reserve the .lit8 or .lit4 sections at all, in order to
entire global offset table. */ reserve the entire global offset table. When
generating embedded PIC code, we use the .lit8
section but not the .lit4 section (we can do .lit4
inline easily; we need to put .lit8 somewhere in
the data segment, and using .lit8 permits the
linker to eventually combine identical .lit8
entries). */
f64 = *args == 'F' || *args == 'L'; f64 = *args == 'F' || *args == 'L';
@ -4264,7 +4398,7 @@ mips_ip (str, ip)
assert (length == (f64 ? 8 : 4)); assert (length == (f64 ? 8 : 4));
if (*args == 'f' if (*args == 'f'
|| (mips_pic != 0 && *args == 'l')) || (mips_pic != NO_PIC && *args == 'l'))
{ {
imm_expr.X_op = O_constant; imm_expr.X_op = O_constant;
if (byte_order == LITTLE_ENDIAN) if (byte_order == LITTLE_ENDIAN)
@ -4292,13 +4426,13 @@ mips_ip (str, ip)
{ {
default: /* unused default case avoids warnings. */ default: /* unused default case avoids warnings. */
case 'L': case 'L':
newname = (mips_pic == 0 ? ".lit8" : ".rdata"); newname = (mips_pic != SVR4_PIC ? ".lit8" : ".rdata");
break; break;
case 'F': case 'F':
newname = ".rdata"; newname = ".rdata";
break; break;
case 'l': case 'l':
assert (mips_pic == 0); assert (mips_pic == NO_PIC);
newname = ".lit4"; newname = ".lit4";
break; break;
} }
@ -4359,15 +4493,28 @@ mips_ip (str, ip)
} }
else else
{ {
int more;
offsetT max;
/* The upper bound should be 0x8000, but /* The upper bound should be 0x8000, but
unfortunately the MIPS assembler accepts numbers unfortunately the MIPS assembler accepts numbers
from 0x8000 to 0xffff and sign extends them, and from 0x8000 to 0xffff and sign extends them, and
we want to be compatible. */ we want to be compatible. We only permit this
extended range for an instruction which does not
provide any further alternates, since those
alternates may handle other cases. People should
use the numbers they mean, rather than relying on
a mysterious sign extension. */
more = (insn + 1 < &mips_opcodes[NUMOPCODES] &&
strcmp (insn->name, insn[1].name) == 0);
if (more)
max = 0x8000;
else
max = 0x10000;
if (imm_expr.X_add_number < -0x8000 || if (imm_expr.X_add_number < -0x8000 ||
imm_expr.X_add_number >= 0x10000) imm_expr.X_add_number >= max)
{ {
if (insn + 1 < &mips_opcodes[NUMOPCODES] && if (more)
!strcmp (insn->name, insn[1].name))
break; break;
as_bad ("16 bit expression not in range -32768..32767"); as_bad ("16 bit expression not in range -32768..32767");
} }
@ -4766,11 +4913,43 @@ md_parse_option (argP, cntP, vecP)
return 1; return 1;
} }
/* Argument -membedded-pic means to use EMBEDDED_PIC. */
if (strcmp (*argP, "membedded-pic") == 0)
{
mips_pic = EMBEDDED_PIC;
*argP = "";
return 1;
}
#ifdef OBJ_ELF
/* When generating ELF code, we permit -KPIC and -call_shared to
select SVR4_PIC, and -non_shared to select no PIC. This is
intended to be compatible with Irix 5. */
if (strcmp (*argP, "KPIC") == 0
|| strcmp (*argP, "call_shared") == 0)
{
mips_pic = SVR4_PIC;
if (g_switch_seen && g_switch_value != 0)
as_warn ("-G may not be used with SVR4 PIC code");
g_switch_value = 0;
bfd_set_gp_size (stdoutput, 0);
*argP = "";
return 1;
}
else if (strcmp (*argP, "non_shared") == 0)
{
mips_pic = NO_PIC;
*argP = "";
return 1;
}
#endif /* OBJ_ELF */
#ifdef GPOPT #ifdef GPOPT
if (**argP == 'G') if (**argP == 'G')
{ {
if ((*argP)[1] != '\0') if (mips_pic == SVR4_PIC)
as_warn ("-G may not be used with SVR4 PIC code");
else if ((*argP)[1] != '\0')
g_switch_value = atoi (*argP + 1); g_switch_value = atoi (*argP + 1);
else if (*cntP) else if (*cntP)
{ {
@ -5241,14 +5420,20 @@ s_option (x)
} }
else if (strncmp (opt, "pic", 3) == 0) else if (strncmp (opt, "pic", 3) == 0)
{ {
mips_pic = atoi (opt + 3); int i;
/* Supposedly no other values are used. */
assert (mips_pic == 0 || mips_pic == 2);
if (mips_pic == 2) i = atoi (opt + 3);
if (i == 0)
mips_pic = NO_PIC;
else if (i == 2)
mips_pic = SVR4_PIC;
else
as_bad (".option pic%d not supported", i);
if (mips_pic == SVR4_PIC)
{ {
if (g_switch_seen && g_switch_value != 0) if (g_switch_seen && g_switch_value != 0)
as_warn ("-G may not be used with PIC code"); as_warn ("-G may not be used with SVR4 PIC code");
g_switch_value = 0; g_switch_value = 0;
bfd_set_gp_size (stdoutput, 0); bfd_set_gp_size (stdoutput, 0);
} }
@ -5361,7 +5546,11 @@ static void
s_abicalls (ignore) s_abicalls (ignore)
int ignore; int ignore;
{ {
mips_pic = 2; mips_pic = SVR4_PIC;
if (g_switch_seen && g_switch_value != 0)
as_warn ("-G may not be used with SVR4 PIC code");
g_switch_value = 0;
bfd_set_gp_size (stdoutput, 0);
demand_empty_rest_of_line (); demand_empty_rest_of_line ();
} }
@ -5382,8 +5571,8 @@ s_cpload (ignore)
expressionS ex; expressionS ex;
int icnt = 0; int icnt = 0;
/* If we are not generating PIC code, .cpload is ignored. */ /* If we are not generating SVR4 PIC code, .cpload is ignored. */
if (mips_pic == 0) if (mips_pic != SVR4_PIC)
{ {
s_ignore (0); s_ignore (0);
return; return;
@ -5419,8 +5608,8 @@ s_cprestore (ignore)
expressionS ex; expressionS ex;
int icnt = 0; int icnt = 0;
/* If we are not generating PIC code, .cprestore is ignored. */ /* If we are not generating SVR4 PIC code, .cprestore is ignored. */
if (mips_pic == 0) if (mips_pic != SVR4_PIC)
{ {
s_ignore (0); s_ignore (0);
return; return;
@ -5452,7 +5641,7 @@ s_gpword (ignore)
char *p; char *p;
/* When not generating PIC code, this is treated as .word. */ /* When not generating PIC code, this is treated as .word. */
if (mips_pic == 0) if (mips_pic == NO_PIC)
{ {
s_cons (2); s_cons (2);
return; return;
@ -5491,7 +5680,7 @@ s_cpadd (ignore)
int reg; int reg;
/* This is ignored when not generating SVR4 PIC code. */ /* This is ignored when not generating SVR4 PIC code. */
if (mips_pic == 0) if (mips_pic == NO_PIC)
{ {
s_ignore (0); s_ignore (0);
return; return;
@ -5575,7 +5764,7 @@ md_estimate_size_before_relax (fragp, segtype)
{ {
int change; int change;
if (mips_pic == 0) if (mips_pic == NO_PIC)
{ {
#ifdef GPOPT #ifdef GPOPT
const char *symname; const char *symname;
@ -5618,7 +5807,7 @@ md_estimate_size_before_relax (fragp, segtype)
change = 1; change = 1;
#endif /* ! defined (GPOPT) */ #endif /* ! defined (GPOPT) */
} }
else else if (mips_pic == SVR4_PIC)
{ {
asection *symsec = fragp->fr_symbol->bsym->section; asection *symsec = fragp->fr_symbol->bsym->section;
@ -5627,6 +5816,8 @@ md_estimate_size_before_relax (fragp, segtype)
&& symsec != &bfd_abs_section && symsec != &bfd_abs_section
&& ! bfd_is_com_section (symsec)); && ! bfd_is_com_section (symsec));
} }
else
abort ();
if (change) if (change)
{ {
@ -5667,7 +5858,7 @@ tc_gen_reloc (section, fixp)
if (fixp->fx_pcrel == 0) if (fixp->fx_pcrel == 0)
reloc->addend = fixp->fx_addnumber; reloc->addend = fixp->fx_addnumber;
else else
#ifdef OBJ_ELF #ifndef OBJ_AOUT
reloc->addend = 0; reloc->addend = 0;
#else #else
reloc->addend = -reloc->address; reloc->addend = -reloc->address;
@ -5716,12 +5907,12 @@ tc_gen_reloc (section, fixp)
reloc3->address += 4; reloc3->address += 4;
} }
if (mips_pic == 0) if (mips_pic == NO_PIC)
{ {
assert (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL); assert (fixp->fx_r_type == BFD_RELOC_MIPS_GPREL);
fixp->fx_r_type = BFD_RELOC_HI16_S; fixp->fx_r_type = BFD_RELOC_HI16_S;
} }
else else if (mips_pic == SVR4_PIC)
{ {
if (fixp->fx_r_type != BFD_RELOC_MIPS_GOT16) if (fixp->fx_r_type != BFD_RELOC_MIPS_GOT16)
{ {
@ -5729,9 +5920,20 @@ tc_gen_reloc (section, fixp)
fixp->fx_r_type = BFD_RELOC_MIPS_GOT16; fixp->fx_r_type = BFD_RELOC_MIPS_GOT16;
} }
} }
else
abort ();
} }
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type); /* To support a PC relative reloc when generating embedded PIC code
for ECOFF, we use a Cygnus extension. We check for that here to
make sure that we don't let such a reloc escape normally. */
#ifdef OBJ_ECOFF
if (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2
&& mips_pic != EMBEDDED_PIC)
reloc->howto = NULL;
else
#endif
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == NULL) if (reloc->howto == NULL)
{ {
@ -5803,7 +6005,7 @@ mips_elf_final_processing ()
sort of BFD interface for this. */ sort of BFD interface for this. */
if (mips_any_noreorder) if (mips_any_noreorder)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NOREORDER; elf_elfheader (stdoutput)->e_flags |= EF_MIPS_NOREORDER;
if (mips_pic != 0) if (mips_pic != NO_PIC)
elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC; elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC;
} }