From 9117d2197e67b24a86d8a48e489e4463a6151220 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Sun, 11 Feb 2001 23:11:41 +0000 Subject: [PATCH] Apply several patches from Maciej W. Rozycki --- bfd/ChangeLog | 33 +++++++++++++++ bfd/elf32-mips.c | 113 +++++++++++++++++++++++++++++++++++---------------- gas/ChangeLog | 9 ++++ gas/config/tc-mips.c | 30 ++++++++++---- opcodes/ChangeLog | 7 ++++ opcodes/mips-dis.c | 6 +-- 6 files changed, 152 insertions(+), 46 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 05740c1..a96c3da 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,36 @@ +2001-02-11 Maciej W. Rozycki + + * elf32-mips.c (mips_elf_create_dynamic_relocation): Undo patch + from 2000-10-13. Do not add the symbol's value for R_MIPS_REL32 + relocations against dynsym symbols. + + * elf32-mips.c (elf_mips_howto_table): Fix the comment on + the R_MIPS_26 relocation. + (mips_elf_calculate_relocation): Use (p + 4) instead of p for + the R_MIPS_26 relocation. + (mips_elf_perform_relocation): Fix the comment on the R_MIPS16_26 + relocation. + * elf64-mips.c (mips_elf64_howto_table_rel): Fix the comment on + the R_MIPS_26 relocation. + (mips_elf64_howto_table_rela): Likewise. + + * elf32-mips.c (struct mips_elf_link_hash_entry): Added no_fn_stub + member to mark symbols that have non-CALL relocations against + them. + (mips_elf_link_hash_newfunc): Initialize no_fn_stub. + (mips_elf_calculate_relocation): Handle R_MIPS_CALL16 like + R_MIPS_GOT16. + (_bfd_mips_elf_check_relocs): Set no_fn_stub for a symbol if a + non-CALL relocation against it is encountered. + (_bfd_mips_elf_copy_indirect_symbol): Merge no_fn_stub as well. + (_bfd_mips_elf_adjust_dynamic_symbol): Only create a stub if + no_fn_stub is not set. + + * elf32-mips.c (mips_elf_output_extsym): Get the output section + information from the real symbol for indirect ones. + Check no_fn_stub to find out if a symbol has a function stub + indeed. + 2001-02-11 Michael Sokolov * Makefile.am (stamp-lib): ranlib the libbfd.a in the build directory. diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 5bb1e94..7eb8aa2 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -80,6 +80,12 @@ struct mips_elf_link_hash_entry section) against this symbol. */ unsigned int min_dyn_reloc_index; + /* We must not create a stub for a symbol that has relocations + related to taking the function's address, i.e. any but + R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition", + p. 4-20. */ + boolean no_fn_stub; + /* If there is a stub that 32 bit functions should use to call this 16 bit function, this points to the section containing the stub. */ asection *fn_stub; @@ -193,7 +199,7 @@ static bfd_vma mips_elf_got16_entry static boolean mips_elf_create_dynamic_relocation PARAMS ((bfd *, struct bfd_link_info *, const Elf_Internal_Rela *, struct mips_elf_link_hash_entry *, asection *, - bfd_vma, bfd_vma *, asection *, boolean local_p)); + bfd_vma, bfd_vma *, asection *)); static void mips_elf_allocate_dynamic_relocations PARAMS ((bfd *, unsigned int)); static boolean mips_elf_stub_section_p @@ -531,7 +537,7 @@ static reloc_howto_type elf_mips_howto_table[] = complain_overflow_dont, /* complain_on_overflow */ /* This needs complex overflow detection, because the upper four - bits must match the PC. */ + bits must match the PC + 4. */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_26", /* name */ true, /* partial_inplace */ @@ -3955,6 +3961,7 @@ mips_elf_link_hash_newfunc (entry, table, string) ret->esym.ifd = -2; ret->possibly_dynamic_relocs = 0; ret->min_dyn_reloc_index = 0; + ret->no_fn_stub = false; ret->fn_stub = NULL; ret->need_fn_stub = false; ret->call_stub = NULL; @@ -4330,24 +4337,36 @@ mips_elf_output_extsym (h, data) } else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) { - /* Set type and value for a symbol with a function stub. */ - h->esym.asym.st = stProc; - sec = h->root.root.u.def.section; - if (sec == NULL) - h->esym.asym.value = 0; - else + struct mips_elf_link_hash_entry *hd = h; + boolean no_fn_stub = h->no_fn_stub; + + while (hd->root.root.type == bfd_link_hash_indirect) { - output_section = sec->output_section; - if (output_section != NULL) - h->esym.asym.value = (h->root.plt.offset - + sec->output_offset - + output_section->vma); - else - h->esym.asym.value = 0; + hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link; + no_fn_stub = no_fn_stub || hd->no_fn_stub; } + + if (!no_fn_stub) + { + /* Set type and value for a symbol with a function stub. */ + h->esym.asym.st = stProc; + sec = hd->root.root.u.def.section; + if (sec == NULL) + h->esym.asym.value = 0; + else + { + output_section = sec->output_section; + if (output_section != NULL) + h->esym.asym.value = (hd->root.plt.offset + + sec->output_offset + + output_section->vma); + else + h->esym.asym.value = 0; + } #if 0 /* FIXME? */ - h->esym.ifd = 0; + h->esym.ifd = 0; #endif + } } if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, @@ -5748,7 +5767,7 @@ mips_elf_next_relocation (r_type, relocation, relend) static boolean mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, - symbol, addendp, input_section, local_p) + symbol, addendp, input_section) bfd *output_bfd; struct bfd_link_info *info; const Elf_Internal_Rela *rel; @@ -5757,7 +5776,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, bfd_vma symbol; bfd_vma *addendp; asection *input_section; - boolean local_p; { Elf_Internal_Rel outrel; boolean skip; @@ -5842,15 +5860,16 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, /* The relocation we're building is section-relative. Therefore, the original addend must be adjusted by the section offset. */ - *addendp += symbol - sec->output_section->vma; + *addendp += section_offset; /* Now, the relocation is just against the section. */ symbol = sec->output_section->vma; } - /* If the relocation is against a local symbol was previously an - absolute relocation, we must adjust it by the value we give - it in the dynamic symbol table. */ - if (local_p && r_type != R_MIPS_REL32) + /* If the relocation was previously an absolute relocation and + this symbol will not be referred to by the relocation, we must + adjust it by the value we give it in the dynamic symbol table. + Otherwise leave the job up to the dynamic linker. */ + if (!indx && r_type != R_MIPS_REL32) *addendp += symbol; /* The relocation is always an REL32 relocation because we don't @@ -6225,7 +6244,7 @@ mips_elf_calculate_relocation (abfd, symbol + addend, sgot->contents + g); } } - else if (r_type == R_MIPS_GOT16) + else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16) /* There's no need to create a local GOT entry here; the calculation for a local GOT16 entry does not involve G. */ break; @@ -6288,7 +6307,7 @@ mips_elf_calculate_relocation (abfd, sec, symbol, &value, - input_section, local_p)) + input_section)) return false; } else @@ -6320,14 +6339,14 @@ mips_elf_calculate_relocation (abfd, break; case R_MIPS16_26: - /* The calculation for R_MIPS_26 is just the same as for an + /* The calculation for R_MIPS16_26 is just the same as for an R_MIPS_26. It's only the storage of the relocated field into the output file that's different. That's handled in mips_elf_perform_relocation. So, we just fall through to the R_MIPS_26 case here. */ case R_MIPS_26: if (local_p) - value = (((addend << 2) | (p & 0xf0000000)) + symbol) >> 2; + value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2; else value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2; value &= howto->dst_mask; @@ -6393,6 +6412,7 @@ mips_elf_calculate_relocation (abfd, break; case R_MIPS_GOT16: + case R_MIPS_CALL16: if (local_p) { boolean forced; @@ -6415,7 +6435,6 @@ mips_elf_calculate_relocation (abfd, /* Fall through. */ - case R_MIPS_CALL16: case R_MIPS_GOT_DISP: value = g; overflowed_p = mips_elf_overflow_p (value, 16); @@ -6620,9 +6639,9 @@ mips_elf_perform_relocation (info, howto, relocation, value, ((sub1 << 16) | sub2)). When producing a relocateable object file, the calculation is - (((A < 2) | (P & 0xf0000000) + S) >> 2) + (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) When producing a fully linked file, the calculation is - let R = (((A < 2) | (P & 0xf0000000) + S) >> 2) + let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff) */ if (!info->relocateable) @@ -7728,10 +7747,10 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) /* We may need a local GOT entry for this relocation. We don't count R_MIPS_GOT_PAGE because we can estimate the maximum number of pages needed by looking at the size of - the segment. Similar comments apply to R_MIPS_GOT16. We - don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because - these are always followed by an R_MIPS_GOT_LO16 or - R_MIPS_CALL_LO16. + the segment. Similar comments apply to R_MIPS_GOT16 and + R_MIPS_CALL16. We don't count R_MIPS_GOT_HI16, or + R_MIPS_CALL_HI16 because these are always followed by an + R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. This estimation is very conservative since we can merge duplicate entries in the GOT. In order to be less @@ -7863,6 +7882,25 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) break; } + /* We must not create a stub for a symbol that has relocations + related to taking the function's address. */ + switch (r_type) + { + default: + if (h != NULL) + { + struct mips_elf_link_hash_entry *mh; + + mh = (struct mips_elf_link_hash_entry *) h; + mh->no_fn_stub = true; + } + break; + case R_MIPS_CALL16: + case R_MIPS_CALL_HI16: + case R_MIPS_CALL_LO16: + break; + } + /* If this reloc is not a 16 bit call, and it has a global symbol, then we will need the fn_stub if there is one. References from a stub section do not count. */ @@ -7998,6 +8036,8 @@ _bfd_mips_elf_copy_indirect_symbol (dir, ind) || (indmips->min_dyn_reloc_index != 0 && indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index)) dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index; + if (indmips->no_fn_stub) + dirmips->no_fn_stub = true; } /* Adjust a symbol defined by a dynamic object and referenced by a @@ -8038,8 +8078,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) mips_elf_allocate_dynamic_relocations (dynobj, hmips->possibly_dynamic_relocs); - /* For a function, create a stub, if needed. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + /* For a function, create a stub, if allowed. */ + if (! hmips->no_fn_stub + && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) { if (! elf_hash_table (info)->dynamic_sections_created) return true; diff --git a/gas/ChangeLog b/gas/ChangeLog index 400085b..d83016a 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,12 @@ +2001-02-11 Maciej W. Rozycki + + * config/tc-mips.c (macro): For M_LA_AB emit a + BFD_RELOC_MIPS_CALL16 relocation or a + BFD_RELOC_MIPS_CALL_HI16/BFD_RELOC_MIPS_CALL_LO16 pair instead of + BFD_RELOC_MIPS_GOT16 and + BFD_RELOC_MIPS_GOT_HI16/BFD_RELOC_MIPS_GOT_LO16, respectively for + loading the jump register when generating SVR4_PIC code. + 2001-02-10 Chris Demetriou * configure.in: Make 'mipself' and 'mipsecoff' emulations diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c index 77ec76f..acc22e2 100644 --- a/gas/config/tc-mips.c +++ b/gas/config/tc-mips.c @@ -3936,7 +3936,7 @@ macro (ip) if (mips_trap) macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", 0, 0); else - macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7); + macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7); return; } @@ -3957,7 +3957,7 @@ macro (ip) macro_build ((char *) NULL, &icnt, NULL, dbl ? "ddiv" : "div", "z,s,t", sreg, treg); - macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7); + macro_build ((char *) NULL, &icnt, NULL, "break", "c", 7); } expr1.X_add_number = -1; macro_build ((char *) NULL, &icnt, &expr1, @@ -3996,7 +3996,7 @@ macro (ip) that later insns are available for delay slot filling. */ --mips_opts.noreorder; - macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6); + macro_build ((char *) NULL, &icnt, NULL, "break", "c", 6); } macro_build ((char *) NULL, &icnt, NULL, s, "d", dreg); break; @@ -4213,9 +4213,13 @@ macro (ip) } else if (mips_pic == SVR4_PIC && ! mips_big_got) { + int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT16; + /* If this is a reference to an external symbol, and there is no constant, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) + or if tempreg is PIC_CALL_REG + lw $tempreg,($gp) (BFD_RELOC_MIPS_CALL16) For a local symbol, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) nop @@ -4242,9 +4246,11 @@ macro (ip) expr1.X_add_number = offset_expr.X_add_number; offset_expr.X_add_number = 0; frag_grow (32); + if (expr1.X_add_number == 0 && tempreg == PIC_CALL_REG) + lw_reloc_type = (int) BFD_RELOC_MIPS_CALL16; macro_build ((char *) NULL, &icnt, &offset_expr, dbl ? "ld" : "lw", - "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT16, GP); + "t,o(b)", tempreg, lw_reloc_type, GP); if (expr1.X_add_number == 0) { int off; @@ -4350,12 +4356,18 @@ macro (ip) else if (mips_pic == SVR4_PIC) { int gpdel; + int lui_reloc_type = (int) BFD_RELOC_MIPS_GOT_HI16; + int lw_reloc_type = (int) BFD_RELOC_MIPS_GOT_LO16; /* 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) addu $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) + addu $tempreg,$tempreg,$gp + lw $tempreg,($tempreg) (BFD_RELOC_MIPS_CALL_LO16) For a local symbol, we want lw $tempreg,($gp) (BFD_RELOC_MIPS_GOT16) nop @@ -4394,8 +4406,13 @@ macro (ip) gpdel = 4; else gpdel = 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, (int) BFD_RELOC_MIPS_GOT_HI16); + tempreg, lui_reloc_type); macro_build ((char *) NULL, &icnt, (expressionS *) NULL, ((bfd_arch_bits_per_address (stdoutput) == 32 || ! ISA_HAS_64BIT_REGS (mips_opts.isa)) @@ -4403,8 +4420,7 @@ macro (ip) "d,v,t", tempreg, tempreg, GP); macro_build ((char *) NULL, &icnt, &offset_expr, dbl ? "ld" : "lw", - "t,o(b)", tempreg, (int) BFD_RELOC_MIPS_GOT_LO16, - tempreg); + "t,o(b)", tempreg, lw_reloc_type, tempreg); if (expr1.X_add_number == 0) { int off; diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 6c93aa7..dfca2e9 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,10 @@ +2001-02-11 Maciej W. Rozycki + + * mips-dis.c (print_insn_arg): Use top four bits of the address of + the following instruction not of the jump itself for the jump + target. + (print_mips16_insn_arg): Likewise. + 2001-02-11 Michael Sokolov * Makefile.am (stamp-lib): ranlib the libopcodes.a in the build diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index a75dc89..849f9f2 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -137,7 +137,7 @@ print_insn_arg (d, l, pc, info) case 'a': (*info->print_address_func) - (((pc & ~ (bfd_vma) 0x0fffffff) + ((((pc + 4) & ~ (bfd_vma) 0x0fffffff) | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)), info); break; @@ -1038,9 +1038,9 @@ print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info) if (! use_extend) extend = 0; l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2); - (*info->print_address_func) ((memaddr & 0xf0000000) | l, info); + (*info->print_address_func) (((memaddr + 4) & 0xf0000000) | l, info); info->insn_type = dis_jsr; - info->target = (memaddr & 0xf0000000) | l; + info->target = ((memaddr + 4) & 0xf0000000) | l; info->branch_delay_insns = 1; break; -- 2.7.4