Daniel Jacobowitz <dan@xxxxxxxxxx> writes: > All comments welcome - Richard, especially from you. How would you > like to proceed? I think the first step should be to get your other > binutils/gcc patches merged, including MIPS16 PIC; I used those as a > base. But see a few of the notes for potential problems with those > patches. Yeah, Nick's approved most of the remaining binutils changes (thanks). I haven't applied them yet because of the doubt over whether st_size should be even or odd for ISA-encoded MIPS16 symbols. I don't really have an opinion, so I'll accept a maintainerly decision... Anyway, the gcc patch looks good to me, thanks. The only niggle I could see was that you didn't update the comment for: +/* True if the output file is marked as ".abicalls; .option pic0" + (-call_mixed). This is a GNU extension. */ +#define TARGET_ABICALLS_PIC0 \ + (TARGET_ABSOLUTE_ABICALLS && TARGET_PLT) (That kind of thing was inevitable given the amount of code you had to wade through. I'm impressed if there's really only one instance!) I think the gcc side is good to go, modulo the _mcount thing. As far as binutils goes, I saw a couple of potential problems: (1) The patch adds the following code to _bfd_mips_elf_create_dynamic_sections: + if (htab->use_plts_and_copy_relocs && htab->root.hplt == NULL) + { + h = _bfd_elf_define_linkage_sym (abfd, info, s, + "_PROCEDURE_LINKAGE_TABLE_"); + htab->root.hplt = h; + if (h == NULL) + return FALSE; + h->type = STT_FUNC; + } But use_plts_and_copy_relocs is only set after all input bfds have been read in. (2) The patch sets pointer_equality_needed as follows: @@ -7432,9 +7484,18 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s elf_hash_table (info)->dynobj = dynobj = abfd; break; } - /* Fall through */ + /* Fall through. */ default: + /* Most static relocations require pointer equality, except + for branches. */ + if (h) + h->pointer_equality_needed = TRUE; + /* Fall through. */ + + case R_MIPS_26: + case R_MIPS_PC16: + case R_MIPS16_26: if (h) ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE; break; But pointer equality is needed for non-call GOT relocations too. I couldn't see anything that explicitly handled that case. I think it would be more robust to set pointer_equality_needed in a separate block, rather than combining it with the existing switch statements. It might then be clearer to set has_nonpic_branches in the new block too, so that you don't need two copies of: if (h && !PIC_OBJECT_P (abfd)) ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE; Some minor nits too: + 0x03990000, /* l[wd] $25, %lo(&GOTPLT[0])($28) */ + 0x01d90000, /* l[wd] $25, %lo(&GOTPLT[0])($14) */ + 0x01d90000, /* l[wd] $25, %lo(&GOTPLT[0])($14) */ These are all fixed as either lw or ld. @@ -1649,13 +1695,16 @@ mips_elf_check_symbols (struct mips_elf_ /* H is a function that might need $25 to be valid on entry. If we're creating a non-PIC relocatable object, mark H as being PIC. If we're creating a non-relocatable object with - non-PIC references to H, make sure that H has an la25 stub. */ + branches to H, make sure that H has an la25 stub. Only + use the stub for branches from non-PIC objects; GCC's + -mno-shared uses branches from PIC objects to functions + which do not require $25. */ if (hti->info->relocatable) { if (!PIC_OBJECT_P (hti->output_bfd)) h->root.other = ELF_ST_SET_MIPS_PIC (h->root.other); } - else if (h->non_pic_ref && !mips_elf_add_la25_stub (hti->info, h)) + else if (h->has_nonpic_branches && !mips_elf_add_la25_stub (hti->info, h)) { hti->error = TRUE; return FALSE; How about something like the following: - non-PIC references to H, make sure that H has an la25 stub. */ + non-PIC branches and jumps to H, make sure that H has an la25 stub. + We specifically ignore branches and jumps from EF_PIC objects, + where the onus is on the compiler or programmer to perform any + necessary initialization of $25. Sometimes such initialization + is unnecessary; for example, -mno-shared functions do not use + the incoming value of $25, and may therefore be called directly. */ (Wordsmith as necessary.) The original wording made it sound like we'd created a stub if there were any branches at all, but that the stub would only be used for branches from non-PIC objects. @@ -2928,6 +2977,7 @@ mips_elf_gotplt_index (struct bfd_link_i struct mips_elf_link_hash_table *htab; htab = mips_elf_hash_table (info); + BFD_ASSERT (htab->is_vxworks); BFD_ASSERT (h->plt.offset != (bfd_vma) -1); /* Calculate the index of the symbol's PLT entry. */ I think this deserves a comment. (It's because the .got.plt address calculation is no longer accurate after the addition of the reserved entries, right?) I realise this function isn't used for non-VxWorks before the patch, but it's a generic concept even so... @@ -4969,6 +5009,14 @@ mips_elf_calculate_relocation (bfd *abfd BFD_ASSERT (sec->size > 0); symbol = sec->output_section->vma + sec->output_offset; } + /* If this is a direct call to a PIC function, redirect to the + non-PIC stub. */ + else if (h != NULL && h->la25_stub && !PIC_OBJECT_P (input_bfd) + && (r_type == R_MIPS_26 || r_type == R_MIPS_PC16 + || r_type == R_MIPS16_26)) + symbol = (h->la25_stub->stub_section->output_section->vma + + h->la25_stub->stub_section->output_offset + + h->la25_stub->offset); /* Calls from 16-bit code to 32-bit code and vice versa require the special jalx instruction. */ I'd prefer to see some part of: (h != NULL && !PIC_OBJECT_P (input_bfd) && (r_type == R_MIPS_26 || r_type == R_MIPS_PC16 || r_type == R_MIPS16_26)) be a separate function that is used both here and in _bfd_mips_elf_check_relocs. At least the r_type check; I don't mind how much else. I just think the reloc code generally is tricky enough that even small decisions like this are worth abstracting out. - htab->plt_header_size = 4 * ARRAY_SIZE (mips_exec_plt0_entry); + htab->plt_header_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry); Probably worth a comment saying that all the plt headers are the same size. It looked a bit odd using something with "o32" in it for n32 and n64. if (h && !PIC_OBJECT_P (abfd)) ((struct mips_elf_link_hash_entry *) h)->has_nonpic_branches = TRUE; + /* Refuse some position-dependent relocations when creating a + shared library. Do not refuse R_MIPS_32 / R_MIPS_64; they're + not PIC, but we can create dynamic relocations and the result + will be fine. Also do not refuse R_MIPS_LO16, which can be + combined with R_MIPS_GOT16. */ + if (info->shared) + { + switch (r_type) + { + case R_MIPS16_HI16: + case R_MIPS_HI16: + case R_MIPS_HIGHER: + case R_MIPS_HIGHEST: + /* Don't refuse a high part relocation if it's against + no symbol (e.g. part of a compound relocation). */ + if (r_symndx == 0) + break; + + /* R_MIPS_HI16 against _gp_disp is used for $gp setup, + and has a special meaning. */ + if (!NEWABI_P (abfd) && h != NULL + && strcmp (h->root.root.string, "_gp_disp") == 0) + break; + + /* FALLTHROUGH */ + + case R_MIPS16_26: + case R_MIPS_26: + howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE); + (*_bfd_error_handler) + (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), + abfd, howto->name, + (h) ? h->root.root.string : "a local symbol"); + bfd_set_error (bfd_error_bad_value); + return FALSE; + default: + break; + } + } FWIW, I thought about adding this too, but rejected it because I was afraid of trapping valid uses. E.g. it makes it impossible to use relocations against SHN_ABS symbols, even though such symbols aren't (generally) subject to runtime relocation. I realise you copied this from other ports though. @@ -8430,10 +8540,16 @@ _bfd_mips_elf_size_dynamic_sections (bfd else if (SGI_COMPAT (output_bfd) && CONST_STRNEQ (name, ".compact_rel")) s->size += mips_elf_hash_table (info)->compact_rel_size; + else if (s == htab->splt) + { + /* If the last PLT entry has a branch delay slot, allocate + room for an extra nop to fill the delay slot. */ + if (!htab->is_vxworks && !info->shared && s->size > 0) + s->size += 4; + } else if (! CONST_STRNEQ (name, ".init") && s != htab->sgot && s != htab->sgotplt - && s != htab->splt && s != htab->sstubs && s != htab->sdynbss) { Why !info->shared? @@ -9604,17 +9727,21 @@ mips_finish_exec_plt (bfd *output_bfd, s gotplt_value_high = ((gotplt_value + 0x8000) >> 16) & 0xffff; gotplt_value_low = gotplt_value & 0xffff; + /* The PLT sequence is not safe for N64 if .got.plt is above the 2GB + mark. */ + BFD_ASSERT ((gotplt_value >> 31) == 0); + /* Pick the load opcode. */ load = MIPS_ELF_LOAD_WORD (output_bfd); /* Install the PLT header. */ loc = htab->splt->contents; - bfd_put_32 (output_bfd, plt_entry[0] | got_value_high, loc); - bfd_put_32 (output_bfd, plt_entry[1] | got_value_low | load, loc + 4); - bfd_put_32 (output_bfd, plt_entry[2] | got_value_low, loc + 8); - bfd_put_32 (output_bfd, plt_entry[3] | gotplt_value_high, loc + 12); + bfd_put_32 (output_bfd, plt_entry[0] | gotplt_value_high, loc); + bfd_put_32 (output_bfd, plt_entry[1] | gotplt_value_low | load, loc + 4); + bfd_put_32 (output_bfd, plt_entry[2] | gotplt_value_low, loc + 8); + bfd_put_32 (output_bfd, plt_entry[3], loc + 12); bfd_put_32 (output_bfd, plt_entry[4], loc + 16); - bfd_put_32 (output_bfd, plt_entry[5] | gotplt_value_low, loc + 20); + bfd_put_32 (output_bfd, plt_entry[5], loc + 20); bfd_put_32 (output_bfd, plt_entry[6], loc + 24); bfd_put_32 (output_bfd, plt_entry[7], loc + 28); } I think it'd be good to tighten the assert, as it would currently trigger for valid X >= -0x80000000 addresses (both in 32-bit and 64-bit code). I don't know of any system out there that allows dynamic executables in kernel space, but I've ceased to be surprised by such things ;) +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ + +bfd_boolean +_bfd_mips_elf_hash_symbol (struct elf_link_hash_entry *h) +{ + struct mips_elf_link_hash_entry *hmips; + + hmips = (struct mips_elf_link_hash_entry *) h; + if (h->plt.offset != MINUS_ONE + && hmips->no_fn_stub + && !h->def_regular + && !h->pointer_equality_needed) + return FALSE; + + return _bfd_elf_hash_symbol (h); +} Were you able to test this, given: static void mips_after_parse (void) { /* .gnu.hash and the MIPS ABI require .dynsym to be sorted in different ways. .gnu.hash needs symbols to be grouped by hash code whereas the MIPS ABI requires a mapping between the GOT and the symbol table. */ if (link_info.emit_gnu_hash) { einfo ("%X%P: .gnu.hash is incompatible with the MIPS ABI\n"); link_info.emit_hash = TRUE; link_info.emit_gnu_hash = FALSE; } after_parse_default (); } ? FWIW, if it's dead code, I'd prefer to leave it out. + printf (_(" Entries:\n")); + printf (_(" %*s %*s %*s %-7s %3s %s\n"), + addr_size * 2, "Address", + addr_size * 2, "Initial", + addr_size * 2, "Sym.Val.", "Type", "Ndx", "Name"); + sym_width = (is_32bit_elf ? 80 : 160) - 28 - addr_size * 6 - 1; "- 17" rather than "- 28"? In the global GOT code, "28 - addr_size * 6" is the width of the format before the final "%s". However, the global GOT entries have an additional 10-char field and space separator, so the width there is 11 greater than here. Index: binutils-mainline/ld/testsuite/ld-mips-elf/pic-and-nonpic-3b.dd =================================================================== --- binutils-mainline.orig/ld/testsuite/ld-mips-elf/pic-and-nonpic-3b.dd 2008-07-16 09:25:17.000000000 -0700 +++ binutils-mainline/ld/testsuite/ld-mips-elf/pic-and-nonpic-3b.dd 2008-07-22 10:43:08.000000000 -0700 @@ -2,50 +2,52 @@ # # -32752: lazy resolution function # -32748: reserved for module pointer -# -32744: PLT resolution function -# -32740: GOT page entry. -# -32736: bar's GOT entry +# -32744: GOT page entry. +# -32740: bar's GOT entry .* Disassembly of section \.plt: -00043010 <.*>: - 43010: 3c0f000a lui t7,0xa - 43014: 8df90008 lw t9,8\(t7\) - 43018: 25ef0008 addiu t7,t7,8 - 4301c: 3c0e0008 lui t6,0x8 - 43020: 03200008 jr t9 - 43024: 25ce1000 addiu t6,t6,4096 - \.\.\. +.* <.*>: +.*: 3c1c0008 lui gp,0x8 +.*: 8f991000 lw t9,4096\(gp\) +.*: 279c1000 addiu gp,gp,4096 +.*: 031cc023 subu t8,t8,gp +.*: 03e07821 move t7,ra +.*: 0018c082 srl t8,t8,0x2 +.*: 0320f809 jalr t9 +.*: 2718fffe addiu t8,t8,-2 + +.* <foo@plt>: +.*: 3c0f0008 lui t7,0x8 +.*: 8df91008 lw t9,4104\(t7\) +.*: 25f81008 addiu t8,t7,4104 +.*: 03200008 jr t9 +.*: 00000000 nop -00043030 <foo@plt>: - 43030: 3c180008 lui t8,0x8 - 43034: 8f191000 lw t9,4096\(t8\) - 43038: 03200008 jr t9 - 4303c: 27181000 addiu t8,t8,4096 Disassembly of section \.text: -00044000 <__start>: - 44000: 0c010c0c jal 43030 <foo@plt> - 44004: 00000000 nop - 44008: 08011004 j 44010 <ext> - 4400c: 00000000 nop - -00044010 <ext>: - 44010: 3c1c000a lui gp,0xa - 44014: 279c7ff0 addiu gp,gp,32752 - 44018: 8f82801c lw v0,-32740\(gp\) - 4401c: 24421000 addiu v0,v0,4096 - 44020: 8f998020 lw t9,-32736\(gp\) - 44024: 03200008 jr t9 - 44028: 00000000 nop - 4402c: 00000000 nop +.* <__start>: +.*: 0c010c10 jal 43040 <foo@plt> +.*: 00000000 nop +.*: 08011004 j 44010 <ext> +.*: 00000000 nop + +.* <ext>: +.*: 3c1c000a lui gp,0xa +.*: 279c7ff0 addiu gp,gp,32752 +.*: 8f828018 lw v0,-32744\(gp\) +.*: 24421000 addiu v0,v0,4096 +.*: 8f99801c lw t9,-32740\(gp\) +.*: 03200008 jr t9 +.*: 00000000 nop +.*: 00000000 nop Disassembly of section .MIPS.stubs: -00044030 <\.MIPS\.stubs>: - 44030: 8f998010 lw t9,-32752\(gp\) - 44034: 03e07821 move t7,ra - 44038: 0320f809 jalr t9 - 4403c: 24180007 li t8,7 +.* <\.MIPS\.stubs>: +.*: 8f998010 lw t9,-32752\(gp\) +.*: 03e07821 move t7,ra +.*: 0320f809 jalr t9 +.*: 24180007 li t8,7 \.\.\. Please keep the "... <...>:" addresses at least. (You did this in some of the other tests, thanks.) The non-disassembly dumps rely on functions being at certain addresses, and I think it's easier to follow the test if those addresses are explicit in the disassembly. (I've used custom scripts for this sort of test to try to protect them from fluctuations in the size of the dynamic info. The addresses should be pretty stable.) Richard