diff options
Diffstat (limited to 'gas/config/tc-mips.c')
-rw-r--r-- | gas/config/tc-mips.c | 141 |
1 files changed, 56 insertions, 85 deletions
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 9918779..a0ad808 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -189,6 +189,8 @@ struct mips_set_options /* MIPS architecture (CPU) type. Changed by .set arch=FOO, the -march command line option, and the default CPU. */ int arch; + /* True if ".set sym32" is in effect. */ + bfd_boolean sym32; }; /* True if -mgp32 was passed. */ @@ -203,7 +205,7 @@ static int file_mips_fp32 = -1; static struct mips_set_options mips_opts = { - ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN + ISA_UNKNOWN, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, CPU_UNKNOWN, FALSE }; /* These variables are filled in with the masks of registers used. @@ -286,13 +288,16 @@ static int mips_32bitmode = 0; /* True if relocations are stored in-place. */ #define HAVE_IN_PLACE_ADDENDS (!HAVE_NEWABI) -/* We can only have 64bit addresses if the object file format supports it. */ -#define HAVE_32BIT_ADDRESSES \ - (HAVE_32BIT_GPRS \ - || (bfd_arch_bits_per_address (stdoutput) == 32 \ - || ! HAVE_64BIT_OBJECTS)) \ +/* The ABI-derived address size. */ +#define HAVE_64BIT_ADDRESSES \ + (HAVE_64BIT_GPRS && (mips_abi == EABI_ABI || mips_abi == N64_ABI)) +#define HAVE_32BIT_ADDRESSES (!HAVE_64BIT_ADDRESSES) -#define HAVE_64BIT_ADDRESSES (! HAVE_32BIT_ADDRESSES) +/* The size of symbolic constants (i.e., expressions of the form + "SYMBOL" or "SYMBOL + OFFSET"). */ +#define HAVE_32BIT_SYMBOLS \ + (HAVE_32BIT_ADDRESSES || !HAVE_64BIT_OBJECTS || mips_opts.sym32) +#define HAVE_64BIT_SYMBOLS (!HAVE_32BIT_SYMBOLS) /* Addresses are loaded in different ways, depending on the address size in use. The n32 ABI Documentation also mandates the use of additions @@ -3864,7 +3869,7 @@ load_address (int reg, expressionS *ep, int *used_at) For GP relative symbols in 64bit address space we can use the same sequence as in 32bit address space. */ - if (HAVE_64BIT_ADDRESSES) + if (HAVE_64BIT_SYMBOLS) { if ((valueT) ep->X_add_number <= MAX_GPREL_OFFSET && !nopic_need_relax (ep->X_add_symbol, 1)) @@ -4922,8 +4927,7 @@ macro (struct mips_cl_insn *ip) && offset_expr.X_add_number >= -0x8000 && offset_expr.X_add_number < 0x8000) { - macro_build (&offset_expr, - (dbl || HAVE_64BIT_ADDRESSES) ? "daddiu" : "addiu", + macro_build (&offset_expr, ADDRESS_ADDI_INSN, "t,r,j", treg, sreg, BFD_RELOC_LO16); break; } @@ -4946,10 +4950,7 @@ macro (struct mips_cl_insn *ip) } if (offset_expr.X_op == O_constant) - load_register (tempreg, &offset_expr, - (mips_pic == NO_PIC - ? (dbl || HAVE_64BIT_ADDRESSES) - : HAVE_64BIT_ADDRESSES)); + load_register (tempreg, &offset_expr, HAVE_64BIT_ADDRESSES); else if (mips_pic == NO_PIC) { /* If this is a reference to a GP relative symbol, we want @@ -4979,7 +4980,7 @@ macro (struct mips_cl_insn *ip) For GP relative symbols in 64bit address space we can use the same sequence as in 32bit address space. */ - if (HAVE_64BIT_ADDRESSES) + if (HAVE_64BIT_SYMBOLS) { if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET && !nopic_need_relax (offset_expr.X_add_symbol, 1)) @@ -5504,16 +5505,7 @@ macro (struct mips_cl_insn *ip) abort (); if (breg != 0) - { - char *s; - - if (mips_pic == NO_PIC) - s = (dbl || HAVE_64BIT_ADDRESSES) ? "daddu" : "addu"; - else - s = ADDRESS_ADD_INSN; - - macro_build (NULL, s, "d,v,t", treg, tempreg, breg); - } + macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", treg, tempreg, breg); break; case M_J_A: @@ -5882,22 +5874,6 @@ macro (struct mips_cl_insn *ip) else fmt = "t,o(b)"; - /* Sign-extending 32-bit constants makes their handling easier. - The HAVE_64BIT_GPRS... part is due to the linux kernel hack - described below. */ - if ((! HAVE_64BIT_ADDRESSES - && (! HAVE_64BIT_GPRS && offset_expr.X_op == O_constant)) - && (offset_expr.X_op == O_constant) - && ! ((offset_expr.X_add_number & ~((bfd_vma) 0x7fffffff)) - == ~((bfd_vma) 0x7fffffff))) - { - if (offset_expr.X_add_number & ~((bfd_vma) 0xffffffff)) - as_bad (_("constant too large")); - - offset_expr.X_add_number = (((offset_expr.X_add_number & 0xffffffff) - ^ 0x80000000) - 0x80000000); - } - if (offset_expr.X_op != O_constant && offset_expr.X_op != O_symbol) { @@ -5907,8 +5883,21 @@ macro (struct mips_cl_insn *ip) /* A constant expression in PIC code can be handled just as it is in non PIC code. */ - if (mips_pic == NO_PIC - || offset_expr.X_op == O_constant) + if (offset_expr.X_op == O_constant) + { + if (HAVE_32BIT_ADDRESSES + && !IS_SEXT_32BIT_NUM (offset_expr.X_add_number)) + as_bad (_("constant too large")); + + expr1.X_add_number = ((offset_expr.X_add_number + 0x8000) + & ~(bfd_vma) 0xffff); + load_register (tempreg, &expr1, HAVE_64BIT_ADDRESSES); + if (breg != 0) + macro_build (NULL, ADDRESS_ADD_INSN, "d,v,t", + tempreg, tempreg, breg); + macro_build (&offset_expr, s, fmt, treg, BFD_RELOC_LO16, tempreg); + } + else if (mips_pic == NO_PIC) { /* If this is a reference to a GP relative symbol, and there is no base register, we want @@ -5964,42 +5953,10 @@ macro (struct mips_cl_insn *ip) <op> $treg,<sym>($tempreg) (BFD_RELOC_LO16) For GP relative symbols in 64bit address space we can use - the same sequence as in 32bit address space. - - If we have 64-bit addresses, as an optimization, for - addresses which are 32-bit constants (e.g. kseg0/kseg1 - addresses) we fall back to the 32-bit address generation - mechanism since it is more efficient. Note that due to - the signed offset used by memory operations, the 32-bit - range is shifted down by 32768 here. This code should - probably attempt to generate 64-bit constants more - efficiently in general. - - As an extension for architectures with 64-bit registers, - we don't truncate 64-bit addresses given as literal - constants down to 32 bits, to support existing practice - in the mips64 Linux (the kernel), that compiles source - files with -mabi=64, assembling them as o32 or n32 (with - -Wa,-32 or -Wa,-n32). This is not beautiful, but since - the whole kernel is loaded into a memory region that is - addressable with sign-extended 32-bit addresses, it is - wasteful to compute the upper 32 bits of every - non-literal address, that takes more space and time. - Some day this should probably be implemented as an - assembler option, such that the kernel doesn't have to - use such ugly hacks, even though it will still have to - end up converting the binary to ELF32 for a number of - platforms whose boot loaders don't support ELF64 - binaries. */ - if ((HAVE_64BIT_ADDRESSES - && ! (offset_expr.X_op == O_constant - && IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000))) - || (HAVE_64BIT_GPRS - && offset_expr.X_op == O_constant - && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000))) + the same sequence as in 32bit address space. */ + if (HAVE_64BIT_SYMBOLS) { - if (offset_expr.X_op == O_symbol - && (valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET + if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET && !nopic_need_relax (offset_expr.X_add_symbol, 1)) { relax_start (offset_expr.X_add_symbol); @@ -6056,10 +6013,6 @@ macro (struct mips_cl_insn *ip) break; } - if (offset_expr.X_op == O_constant - && ! IS_SEXT_32BIT_NUM (offset_expr.X_add_number + 0x8000)) - as_bad (_("load/store address overflow (max 32 bits)")); - if (breg == 0) { if ((valueT) offset_expr.X_add_number <= MAX_GPREL_OFFSET @@ -10241,10 +10194,14 @@ struct option md_longopts[] = #define OPTION_MNO_SHARED (OPTION_MISC_BASE + 13) {"mshared", no_argument, NULL, OPTION_MSHARED}, {"mno-shared", no_argument, NULL, OPTION_MNO_SHARED}, +#define OPTION_MSYM32 (OPTION_MISC_BASE + 14) +#define OPTION_MNO_SYM32 (OPTION_MISC_BASE + 15) + {"msym32", no_argument, NULL, OPTION_MSYM32}, + {"mno-sym32", no_argument, NULL, OPTION_MNO_SYM32}, /* ELF-specific options. */ #ifdef OBJ_ELF -#define OPTION_ELF_BASE (OPTION_MISC_BASE + 14) +#define OPTION_ELF_BASE (OPTION_MISC_BASE + 16) #define OPTION_CALL_SHARED (OPTION_ELF_BASE + 0) {"KPIC", no_argument, NULL, OPTION_CALL_SHARED}, {"call_shared", no_argument, NULL, OPTION_CALL_SHARED}, @@ -10465,6 +10422,14 @@ md_parse_option (int c, char *arg) mips_in_shared = FALSE; break; + case OPTION_MSYM32: + mips_opts.sym32 = TRUE; + break; + + case OPTION_MNO_SYM32: + mips_opts.sym32 = FALSE; + break; + #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 @@ -11814,6 +11779,10 @@ s_mipsset (int x ATTRIBUTE_UNUSED) free (s); } } + else if (strcmp (name, "sym32") == 0) + mips_opts.sym32 = TRUE; + else if (strcmp (name, "nosym32") == 0) + mips_opts.sym32 = FALSE; else { as_warn (_("Tried to set unrecognized symbol: %s\n"), name); @@ -11880,7 +11849,7 @@ s_cpload (int ignore ATTRIBUTE_UNUSED) /* If we need to produce a 64-bit address, we are better off using the default instruction sequence. */ - in_shared = mips_in_shared || HAVE_64BIT_ADDRESSES; + in_shared = mips_in_shared || HAVE_64BIT_SYMBOLS; ex.X_op = O_symbol; ex.X_add_symbol = symbol_find_or_make (in_shared ? "_gp_disp" : "_gp"); @@ -11984,7 +11953,7 @@ s_cpsetup (int ignore ATTRIBUTE_UNUSED) macro_build (NULL, "daddu", "d,v,t", mips_cpreturn_register, mips_gp_register, 0); - if (mips_in_shared || HAVE_64BIT_ADDRESSES) + if (mips_in_shared || HAVE_64BIT_SYMBOLS) { macro_build (&ex_sym, "lui", "t,u", mips_gp_register, -1, BFD_RELOC_GPREL16, BFD_RELOC_MIPS_SUB, @@ -14136,6 +14105,8 @@ MIPS options:\n\ -mfix-vr4120 work around certain VR4120 errata\n\ -mgp32 use 32-bit GPRs, regardless of the chosen ISA\n\ -mfp32 use 32-bit FPRs, regardless of the chosen ISA\n\ +-mno-shared optimize output for executables\n\ +-msym32 assume all symbols have 32-bit values\n\ -O0 remove unneeded NOPs, do not swap branches\n\ -O remove unneeded NOPs and swap branches\n\ --[no-]construct-floats [dis]allow floating point values to be constructed\n\ |