From 197b9ca0f9e5441116d79731c6081e219b4c7c60 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Thu, 15 Jul 1999 13:12:02 +0000 Subject: [PATCH] * elf32-mips.c (mips_elf_stub_section_p): New function. (mips_elf_calculate_relocation): Handle MIPS16 stub functions. (mips_elf_relocate_section): Adjust calling sequence for mips_elf_calculate_relocation and mips_elf_perform_relocation. (mips_elf_perform_relocation): Turn `jal' into `jalx' where required. --- bfd/ChangeLog | 9 +++ bfd/elf32-mips.c | 164 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 159 insertions(+), 14 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 7b0d398bbb4..147ad465af3 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,12 @@ +1999-07-15 Mark Mitchell + + * elf32-mips.c (mips_elf_stub_section_p): New function. + (mips_elf_calculate_relocation): Handle MIPS16 stub functions. + (mips_elf_relocate_section): Adjust calling sequence for + mips_elf_calculate_relocation and mips_elf_perform_relocation. + (mips_elf_perform_relocation): Turn `jal' into `jalx' where + required. + 1999-07-15 Ian Lance Taylor * configure.in: Bump version number to 2.9.5. diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 8f45fe114c9..06a4de82742 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -168,13 +168,14 @@ static boolean mips_elf_next_lo16_addend static bfd_reloc_status_type mips_elf_calculate_relocation PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *, const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *, - Elf_Internal_Sym *, asection **, bfd_vma *, const char **)); + Elf_Internal_Sym *, asection **, bfd_vma *, const char **, + boolean *)); static bfd_vma mips_elf_obtain_contents PARAMS ((reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *)); -static void mips_elf_perform_relocation +static boolean mips_elf_perform_relocation PARAMS ((struct bfd_link_info *, reloc_howto_type *, const Elf_Internal_Rela *, bfd_vma, - bfd *, bfd_byte *)); + bfd *, asection *, bfd_byte *, boolean)); static boolean mips_elf_assign_gp PARAMS ((bfd *, bfd_vma *)); static boolean mips_elf_sort_hash_table_f PARAMS ((struct mips_elf_link_hash_entry *, PTR)); @@ -192,6 +193,8 @@ static unsigned int mips_elf_create_dynamic_relocation long, bfd_vma, asection *)); static void mips_elf_allocate_dynamic_relocations PARAMS ((bfd *, unsigned int)); +static boolean mips_elf_stub_section_p + PARAMS ((bfd *, asection *)); /* The level of IRIX compatibility we're striving for. */ @@ -5662,6 +5665,8 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, dynindx, RELOCATION; RELOCATION->R_ADDEND is ignored. The result of the relocation calculation is stored in VALUEP. + REQUIRE_JALXP indicates whether or not the opcode used with this + relocation must be JALX. This function returns bfd_reloc_continue if the caller need take no further action regarding this relocation, bfd_reloc_notsupported if @@ -5679,7 +5684,8 @@ mips_elf_calculate_relocation (abfd, local_syms, local_sections, valuep, - namep) + namep, + require_jalxp) bfd *abfd; bfd *input_bfd; asection *input_section; @@ -5691,6 +5697,7 @@ mips_elf_calculate_relocation (abfd, asection **local_sections; bfd_vma *valuep; const char **namep; + boolean *require_jalxp; { /* The eventual value we will return. */ bfd_vma value; @@ -5725,6 +5732,8 @@ mips_elf_calculate_relocation (abfd, /* True if overflow occurred during the calculation of the relocation value. */ boolean overflowed_p; + /* True if this relocation refers to a MIPS16 function. */ + boolean target_is_16_bit_code_p = false; /* Parse the relocation. */ r_symndx = ELF32_R_SYM (relocation->r_info); @@ -5773,6 +5782,8 @@ mips_elf_calculate_relocation (abfd, sym->st_name); if (*namep == '\0') *namep = bfd_section_name (input_bfd, sec); + + target_is_16_bit_code_p = (sym->st_other == STO_MIPS16); } else { @@ -5821,7 +5832,73 @@ mips_elf_calculate_relocation (abfd, input_section, relocation->r_offset); return bfd_reloc_undefined; } + + target_is_16_bit_code_p = (h->root.other == STO_MIPS16); + } + + /* If this is a 32-bit call to a 16-bit function with a stub, we + need to redirect the call to the stub, unless we're already *in* + a stub. */ + if (r_type != R_MIPS16_26 && !info->relocateable + && ((h != NULL && h->fn_stub != NULL) + || (local_p && elf_tdata (input_bfd)->local_stubs != NULL + && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL)) + && !mips_elf_stub_section_p (input_bfd, input_section)) + { + /* This is a 32-bit call to a 16-bit function. We should + have already noticed that we were going to need the + stub. */ + if (local_p) + sec = elf_tdata (input_bfd)->local_stubs[r_symndx]; + else + { + BFD_ASSERT (h->need_fn_stub); + sec = h->fn_stub; + } + + symbol = sec->output_section->vma + sec->output_offset; } + /* If this is a 16-bit call to a 32-bit function with a stub, we + need to redirect the call to the stub. */ + else if (r_type == R_MIPS16_26 && !info->relocateable + && h != NULL + && (h->call_stub != NULL || h->call_fp_stub != NULL) + && !target_is_16_bit_code_p) + { + /* If both call_stub and call_fp_stub are defined, we can figure + out which one to use by seeing which one appears in the input + file. */ + if (h->call_stub != NULL && h->call_fp_stub != NULL) + { + asection *o; + + sec = NULL; + for (o = input_bfd->sections; o != NULL; o = o->next) + { + if (strncmp (bfd_get_section_name (input_bfd, o), + CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0) + { + sec = h->call_fp_stub; + break; + } + } + if (sec == NULL) + sec = h->call_stub; + } + else if (h->call_stub != NULL) + sec = h->call_stub; + else + sec = h->call_fp_stub; + + BFD_ASSERT (sec->_raw_size > 0); + symbol = sec->output_section->vma + sec->output_offset; + } + + /* Calls from 16-bit code to 32-bit code and vice versa require the + special jalx instruction. */ + if (!info->relocateable + && ((r_type == R_MIPS16_26) != target_is_16_bit_code_p)) + *require_jalxp = true; /* If we haven't already determined the GOT offset, or the GP value, and we're going to need it, get it now. */ @@ -6114,22 +6191,28 @@ mips_elf_obtain_contents (howto, relocation, input_bfd, contents) /* It has been determined that the result of the RELOCATION is the VALUE. Use HOWTO to place VALUE into the output file at the appropriate position. The SECTION is the section to which the - relocatin applies. + relocation applies. If REQUIRE_JALX is true, then the opcode used + for the relocation must be either JAL or JALX, and it is + unconditionally converted to JALX. Returns false if anything goes wrong. */ -static void +static boolean mips_elf_perform_relocation (info, howto, relocation, value, - input_bfd, contents) + input_bfd, input_section, + contents, require_jalx) struct bfd_link_info *info; reloc_howto_type *howto; const Elf_Internal_Rela *relocation; bfd_vma value; bfd *input_bfd; + asection *input_section; bfd_byte *contents; + boolean require_jalx; { bfd_vma x; bfd_byte *location; + int r_type = ELF32_R_TYPE (relocation->r_info); /* Figure out where the relocation is occurring. */ location = contents + relocation->r_offset; @@ -6142,7 +6225,7 @@ mips_elf_perform_relocation (info, howto, relocation, value, /* If this is the R_MIPS16_26 relocation, we must store the value in a funny way. */ - if (ELF32_R_TYPE (relocation->r_info) == R_MIPS16_26) + if (r_type == R_MIPS16_26) { /* R_MIPS16_26 is used for the mips16 jal and jalx instructions. Most mips16 instructions are 16 bits, but these instructions @@ -6210,7 +6293,7 @@ mips_elf_perform_relocation (info, howto, relocation, value, | (value & 0xffff)); } - else if (ELF32_R_TYPE (relocation->r_info) == R_MIPS16_GPREL) + else if (r_type == R_MIPS16_GPREL) { /* R_MIPS16_GPREL is used for GP-relative addressing in mips16 mode. A typical instruction will have a format like this: @@ -6239,15 +6322,64 @@ mips_elf_perform_relocation (info, howto, relocation, value, /* Set the field. */ x |= (value & howto->dst_mask); + /* If required, turn JAL into JALX. */ + if (require_jalx) + { + boolean ok; + bfd_vma opcode = x >> 26; + bfd_vma jalx_opcode; + + /* Check to see if the opcode is already JAL or JALX. */ + if (r_type == R_MIPS16_26) + { + ok = ((opcode == 0x6) || (opcode == 0x7)); + jalx_opcode = 0x7; + } + else + { + ok = ((opcode == 0x3) || (opcode == 0x1d)); + jalx_opcode = 0x1d; + } + + /* If the opcode is not JAL or JALX, there's a problem. */ + if (!ok) + { + (*_bfd_error_handler) + (_("%s: %s+0x%lx: jump to stub routine which is not jal"), + bfd_get_filename (input_bfd), + input_section->name, + (unsigned long) relocation->r_offset); + bfd_set_error (bfd_error_bad_value); + return false; + } + + /* Make this the JALX opcode. */ + x = (x & ~(0x3f << 26)) | (jalx_opcode << 26); + } + /* Swap the high- and low-order 16 bits on little-endian systems when doing a MIPS16 relocation. */ - if ((ELF32_R_TYPE (relocation->r_info) == R_MIPS16_GPREL - || ELF32_R_TYPE (relocation->r_info) == R_MIPS16_26) + if ((r_type == R_MIPS16_GPREL || r_type == R_MIPS16_26) && bfd_little_endian (input_bfd)) x = (((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16)); /* Put the value into the output. */ bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location); + return true; +} + +/* Returns true if SECTION is a MIPS16 stub section. */ + +static boolean +mips_elf_stub_section_p (abfd, section) + bfd *abfd; + asection *section; +{ + const char *name = bfd_get_section_name (abfd, section); + + return (strncmp (name, FN_STUB, sizeof FN_STUB - 1) == 0 + || strncmp (name, CALL_STUB, sizeof CALL_STUB - 1) == 0 + || strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0); } /* Relocate a MIPS ELF section. */ @@ -6279,6 +6411,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, const char *name; bfd_vma value; reloc_howto_type *howto; + boolean require_jalx; /* Find the relocation howto for this relocation. */ if (ELF32_R_TYPE (rel->r_info) == R_MIPS_64 @@ -6383,7 +6516,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, local_syms, local_sections, &value, - &name)) + &name, + &require_jalx)) { case bfd_reloc_continue: /* There's nothing to do. */ @@ -6476,8 +6610,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, } /* Actually perform the relocation. */ - mips_elf_perform_relocation (info, howto, rel, value, input_bfd, - contents); + if (!mips_elf_perform_relocation (info, howto, rel, value, input_bfd, + input_section, contents, + require_jalx)) + return false; } return true; -- 2.30.2