diff options
author | Jeff Law <law@redhat.com> | 1993-12-05 03:46:12 +0000 |
---|---|---|
committer | Jeff Law <law@redhat.com> | 1993-12-05 03:46:12 +0000 |
commit | 4861ac76c76444c318454c0f41ff5304fb9a155b (patch) | |
tree | ab6b577bee575214292b4d6e395e9470fb5a2062 /bfd/elf32-hppa.c | |
parent | 48eb5281b59ed83597c5aa75df5a256892af9007 (diff) | |
download | gdb-4861ac76c76444c318454c0f41ff5304fb9a155b.zip gdb-4861ac76c76444c318454c0f41ff5304fb9a155b.tar.gz gdb-4861ac76c76444c318454c0f41ff5304fb9a155b.tar.bz2 |
* elf32-hppa.c: (elf_hppa_howto_table): PLABEL and DLT
relocations are not pc-relative.
Diffstat (limited to 'bfd/elf32-hppa.c')
-rw-r--r-- | bfd/elf32-hppa.c | 1115 |
1 files changed, 604 insertions, 511 deletions
diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c index 87cc948..b677e4d 100644 --- a/bfd/elf32-hppa.c +++ b/bfd/elf32-hppa.c @@ -36,14 +36,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ November 19, 1992. */ -/* - Written by: - - Center for Software Science - Department of Computer Science - University of Utah -*/ - #include "elf32-hppa.h" #include "libhppa.h" #include "aout/aout64.h" @@ -133,20 +125,20 @@ static reloc_howto_type elf_hppa_howto_table[ELF_HOWTO_TABLE_SIZE] = {R_HPPA_PCREL_CALL_RR17, 0, 3, 17, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PCREL_CALL_RR17"}, /* 9.3.8. Plabel relocation types */ - {R_HPPA_PLABEL_32, 0, 3, 32, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_32"}, - {R_HPPA_PLABEL_11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_11"}, - {R_HPPA_PLABEL_14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_14"}, - {R_HPPA_PLABEL_L21, 0, 3, 21, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_L21"}, - {R_HPPA_PLABEL_R11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R11"}, - {R_HPPA_PLABEL_R14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R14"}, + {R_HPPA_PLABEL_32, 0, 3, 32, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_32"}, + {R_HPPA_PLABEL_11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_11"}, + {R_HPPA_PLABEL_14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_14"}, + {R_HPPA_PLABEL_L21, 0, 3, 21, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_L21"}, + {R_HPPA_PLABEL_R11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R11"}, + {R_HPPA_PLABEL_R14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_PLABEL_R14"}, /* 9.3.9. Data linkage table (DLT) relocation types */ - {R_HPPA_DLT_32, 0, 3, 32, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_32"}, - {R_HPPA_DLT_11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_11"}, - {R_HPPA_DLT_14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_14"}, - {R_HPPA_DLT_L21, 0, 3, 21, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_L21"}, - {R_HPPA_DLT_R11, 0, 3, 11, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R11"}, - {R_HPPA_DLT_R14, 0, 3, 14, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R14"}, + {R_HPPA_DLT_32, 0, 3, 32, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_32"}, + {R_HPPA_DLT_11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_11"}, + {R_HPPA_DLT_14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_14"}, + {R_HPPA_DLT_L21, 0, 3, 21, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_L21"}, + {R_HPPA_DLT_R11, 0, 3, 11, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R11"}, + {R_HPPA_DLT_R14, 0, 3, 14, false, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_DLT_R14"}, /* 9.3.10. Relocations for unwinder tables */ {R_HPPA_UNWIND_ENTRY, 0, 3, 32, true, 0, complain_overflow_signed, hppa_elf_reloc, "R_HPPA_UNWIND_ENTRY"}, @@ -1177,28 +1169,24 @@ static asymbol *global_symbol; static int global_sym_defined; static bfd_reloc_status_type -DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, output_bfd), - bfd * abfd AND - arelent * reloc_entry AND - asymbol * symbol_in AND - PTR data AND - asection * input_section AND - bfd * output_bfd) +hppa_elf_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol_in; + PTR data; + asection *input_section; + bfd *output_bfd; { unsigned long insn; long sym_value = 0; - - unsigned long addr = reloc_entry->address; /*+ input_section->vma*/ + unsigned long addr = reloc_entry->address; bfd_byte *hit_data = addr + (bfd_byte *) (data); unsigned short r_type = reloc_entry->howto->type & 0xFF; unsigned short r_field = e_fsel; boolean r_pcrel = reloc_entry->howto->pc_relative; - - /* howto->bitsize contains the format (11, 14, 21, etc) information */ unsigned r_format = reloc_entry->howto->bitsize; long r_addend = reloc_entry->addend; - if (output_bfd) { /* Partial linking - do nothing */ @@ -1206,16 +1194,14 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu return bfd_reloc_ok; } + /* If performing final link and the symbol we're relocating against + is undefined, then return an error. */ if (symbol_in && symbol_in->section == &bfd_und_section) return bfd_reloc_undefined; - /* Check for stubs that might be required. */ - /* symbol_in = hppa_elf_stub_check (abfd, input_section->output_section->owner, reloc_entry); */ - sym_value = get_symbol_value (symbol_in); - /* compute value of $global$ if it is there. */ - + /* Compute the value of $global$. */ if (!global_sym_defined) { if (global_symbol) @@ -1223,83 +1209,85 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu global_value = (global_symbol->value + global_symbol->section->output_section->vma + global_symbol->section->output_offset); - GOT_value = global_value; /* XXX: For HP-UX, GOT==DP */ + GOT_value = global_value; global_sym_defined++; } } - /* get the instruction word */ + /* Get the instruction word. */ insn = bfd_get_32 (abfd, hit_data); - /* relocate the value based on the relocation type */ + /* Relocate the value based on one of the basic relocation types - /* basic_type_1: relocation is relative to $global$ */ - /* basic_type_2: relocation is relative to the current GOT */ - /* basic_type_3: relocation is an absolute call */ - /* basic_type_4: relocation is an PC-relative call */ - /* basic_type_5: relocation is plabel reference */ - /* basic_type_6: relocation is an unwind table relocation */ - /* extended_type: unimplemented */ + basic_type_1: relocation is relative to $global$ + basic_type_2: relocation is relative to the current GOT + basic_type_3: relocation is an absolute call + basic_type_4: relocation is an PC-relative call + basic_type_5: relocation is plabel reference + basic_type_6: relocation is an unwind table relocation + extended_type: unimplemented */ switch (r_type) { case R_HPPA_NONE: break; - case R_HPPA_32: /* Symbol + Addend 32 */ + + /* Handle all the basic type 1 relocations. */ + case R_HPPA_32: r_field = e_fsel; goto do_basic_type_1; - case R_HPPA_11: /* Symbol + Addend 11 */ + case R_HPPA_11: r_field = e_fsel; goto do_basic_type_1; - case R_HPPA_14: /* Symbol + Addend 14 */ + case R_HPPA_14: r_field = e_fsel; goto do_basic_type_1; - case R_HPPA_17: /* Symbol + Addend 17 */ + case R_HPPA_17: r_field = e_fsel; goto do_basic_type_1; - case R_HPPA_L21: /* L (Symbol, Addend) 21 */ + case R_HPPA_L21: r_field = e_lsel; goto do_basic_type_1; - case R_HPPA_R11: /* R (Symbol, Addend) 11 */ + case R_HPPA_R11: r_field = e_rsel; goto do_basic_type_1; - case R_HPPA_R14: /* R (Symbol, Addend) 14 */ + case R_HPPA_R14: r_field = e_rsel; goto do_basic_type_1; - case R_HPPA_R17: /* R (Symbol, Addend) 17 */ + case R_HPPA_R17: r_field = e_rsel; goto do_basic_type_1; - case R_HPPA_LS21: /* LS(Symbol, Addend) 21 */ + case R_HPPA_LS21: r_field = e_lssel; goto do_basic_type_1; - case R_HPPA_RS11: /* RS(Symbol, Addend) 11 */ + case R_HPPA_RS11: r_field = e_rssel; goto do_basic_type_1; - case R_HPPA_RS14: /* RS(Symbol, Addend) 14 */ + case R_HPPA_RS14: r_field = e_rssel; goto do_basic_type_1; - case R_HPPA_RS17: /* RS(Symbol, Addend) 17 */ + case R_HPPA_RS17: r_field = e_ldsel; goto do_basic_type_1; - case R_HPPA_LD21: /* LD(Symbol, Addend) 21 */ + case R_HPPA_LD21: r_field = e_ldsel; goto do_basic_type_1; - case R_HPPA_RD11: /* RD(Symbol, Addend) 11 */ + case R_HPPA_RD11: r_field = e_rdsel; goto do_basic_type_1; - case R_HPPA_RD14: /* RD(Symbol, Addend) 14 */ + case R_HPPA_RD14: r_field = e_rdsel; goto do_basic_type_1; - case R_HPPA_RD17: /* RD(Symbol, Addend) 17 */ + case R_HPPA_RD17: r_field = e_rdsel; goto do_basic_type_1; - case R_HPPA_LR21: /* LR(Symbol, Addend) 21 */ + case R_HPPA_LR21: r_field = e_lrsel; goto do_basic_type_1; - case R_HPPA_RR14: /* RR(Symbol, Addend) 14 */ + case R_HPPA_RR14: r_field = e_rrsel; goto do_basic_type_1; - case R_HPPA_RR17: /* RR(Symbol, Addend) 17 */ + case R_HPPA_RR17: r_field = e_rrsel; do_basic_type_1: @@ -1308,44 +1296,46 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu r_type, r_format, r_field, r_pcrel); break; - case R_HPPA_GOTOFF_11: /* Symbol - GOT + Addend 11 */ + /* Handle all the basic type 2 relocations. */ + case R_HPPA_GOTOFF_11: r_field = e_fsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_14: /* Symbol - GOT + Addend 14 */ + case R_HPPA_GOTOFF_14: r_field = e_fsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_L21: /* L (Sym - GOT, Addend) 21 */ + case R_HPPA_GOTOFF_L21: r_field = e_lsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_R11: /* R (Sym - GOT, Addend) 11 */ + case R_HPPA_GOTOFF_R11: r_field = e_rsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_R14: /* R (Sym - GOT, Addend) 14 */ + case R_HPPA_GOTOFF_R14: r_field = e_rsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_LS21: /* LS(Sym - GOT, Addend) 21 */ + case R_HPPA_GOTOFF_LS21: r_field = e_lssel; goto do_basic_type_2; - case R_HPPA_GOTOFF_RS11: /* RS(Sym - GOT, Addend) 11 */ + case R_HPPA_GOTOFF_RS11: r_field = e_rssel; goto do_basic_type_2; - case R_HPPA_GOTOFF_RS14: /* RS(Sym - GOT, Addend) 14 */ + case R_HPPA_GOTOFF_RS14: r_field = e_rssel; goto do_basic_type_2; - case R_HPPA_GOTOFF_LD21: /* LD(Sym - GOT, Addend) 21 */ + case R_HPPA_GOTOFF_LD21: r_field = e_ldsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_RD11: /* RD(Sym - GOT, Addend) 11 */ + case R_HPPA_GOTOFF_RD11: r_field = e_rdsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_RD14: /* RD(Sym - GOT, Addend) 14 */ + case R_HPPA_GOTOFF_RD14: r_field = e_rdsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_LR21: /* LR(Sym - GOT, Addend) 21 */ + case R_HPPA_GOTOFF_LR21: r_field = e_lrsel; goto do_basic_type_2; - case R_HPPA_GOTOFF_RR14: /* RR(Sym - GOT, Addend) 14 */ + case R_HPPA_GOTOFF_RR14: r_field = e_rrsel; + do_basic_type_2: sym_value -= GOT_value; insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr, @@ -1353,124 +1343,129 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu r_type, r_format, r_field, r_pcrel); break; - case R_HPPA_ABS_CALL_11: /* Symbol + Addend 11 */ + /* Handle all the basic type 3 relocations. */ + case R_HPPA_ABS_CALL_11: r_field = e_fsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_14: /* Symbol + Addend 14 */ + case R_HPPA_ABS_CALL_14: r_field = e_fsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_17: /* Symbol + Addend 17 */ + case R_HPPA_ABS_CALL_17: r_field = e_fsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_L21: /* L (Symbol, Addend) 21 */ + case R_HPPA_ABS_CALL_L21: r_field = e_lsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_R11: /* R (Symbol, Addend) 11 */ + case R_HPPA_ABS_CALL_R11: r_field = e_rsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_R14: /* R (Symbol, Addend) 14 */ + case R_HPPA_ABS_CALL_R14: r_field = e_rsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_R17: /* R (Symbol, Addend) 17 */ + case R_HPPA_ABS_CALL_R17: r_field = e_rsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_LS21: /* LS(Symbol, Addend) 21 */ + case R_HPPA_ABS_CALL_LS21: r_field = e_lssel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RS11: /* RS(Symbol, Addend) 11 */ + case R_HPPA_ABS_CALL_RS11: r_field = e_lssel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RS14: /* RS(Symbol, Addend) 14 */ + case R_HPPA_ABS_CALL_RS14: r_field = e_rssel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RS17: /* RS(Symbol, Addend) 17 */ + case R_HPPA_ABS_CALL_RS17: r_field = e_rssel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_LD21: /* LD(Symbol, Addend) 21 */ + case R_HPPA_ABS_CALL_LD21: r_field = e_ldsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RD11: /* RD(Symbol, Addend) 11 */ + case R_HPPA_ABS_CALL_RD11: r_field = e_rdsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RD14: /* RD(Symbol, Addend) 14 */ + case R_HPPA_ABS_CALL_RD14: r_field = e_rdsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RD17: /* RD(Symbol, Addend) 17 */ + case R_HPPA_ABS_CALL_RD17: r_field = e_rdsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_LR21: /* LR(Symbol, Addend) 21 */ + case R_HPPA_ABS_CALL_LR21: r_field = e_lrsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RR14: /* RR(Symbol, Addend) 14 */ + case R_HPPA_ABS_CALL_RR14: r_field = e_rrsel; goto do_basic_type_3; - case R_HPPA_ABS_CALL_RR17: /* RR(Symbol, Addend) 17 */ + case R_HPPA_ABS_CALL_RR17: r_field = e_rrsel; + do_basic_type_3: insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr, symbol_in, sym_value, r_addend, r_type, r_format, r_field, r_pcrel); break; - case R_HPPA_PCREL_CALL_11: /* Symbol - PC + Addend 11 */ + /* Handle all the basic type 4 relocations. */ + case R_HPPA_PCREL_CALL_11: r_field = e_fsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_14: /* Symbol - PC + Addend 14 */ + case R_HPPA_PCREL_CALL_14: r_field = e_fsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_17: /* Symbol - PC + Addend 17 */ + case R_HPPA_PCREL_CALL_17: r_field = e_fsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_L21:/* L (Symbol - PC, Addend) 21 */ + case R_HPPA_PCREL_CALL_L21: r_field = e_lsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_R11:/* R (Symbol - PC, Addend) 11 */ + case R_HPPA_PCREL_CALL_R11: r_field = e_rsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_R14:/* R (Symbol - PC, Addend) 14 */ + case R_HPPA_PCREL_CALL_R14: r_field = e_rsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_R17:/* R (Symbol - PC, Addend) 17 */ + case R_HPPA_PCREL_CALL_R17: r_field = e_rsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_LS21: /* LS(Symbol - PC, Addend) 21 */ + case R_HPPA_PCREL_CALL_LS21: r_field = e_lssel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RS11: /* RS(Symbol - PC, Addend) 11 */ + case R_HPPA_PCREL_CALL_RS11: r_field = e_rssel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RS14: /* RS(Symbol - PC, Addend) 14 */ + case R_HPPA_PCREL_CALL_RS14: r_field = e_rssel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RS17: /* RS(Symbol - PC, Addend) 17 */ + case R_HPPA_PCREL_CALL_RS17: r_field = e_rssel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_LD21: /* LD(Symbol - PC, Addend) 21 */ + case R_HPPA_PCREL_CALL_LD21: r_field = e_ldsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RD11: /* RD(Symbol - PC, Addend) 11 */ + case R_HPPA_PCREL_CALL_RD11: r_field = e_rdsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RD14: /* RD(Symbol - PC, Addend) 14 */ + case R_HPPA_PCREL_CALL_RD14: r_field = e_rdsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RD17: /* RD(Symbol - PC, Addend) 17 */ + case R_HPPA_PCREL_CALL_RD17: r_field = e_rdsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_LR21: /* LR(Symbol - PC, Addend) 21 */ + case R_HPPA_PCREL_CALL_LR21: r_field = e_lrsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RR14: /* RR(Symbol - PC, Addend) 14 */ + case R_HPPA_PCREL_CALL_RR14: r_field = e_rrsel; goto do_basic_type_4; - case R_HPPA_PCREL_CALL_RR17: /* RR(Symbol - PC, Addend) 17 *//* #69 */ + case R_HPPA_PCREL_CALL_RR17: r_field = e_rrsel; + do_basic_type_4: insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr, symbol_in, sym_value, r_addend, r_type, r_format, r_field, r_pcrel); break; + /* Handle all the basic type 5 relocations. */ case R_HPPA_PLABEL_32: case R_HPPA_PLABEL_11: case R_HPPA_PLABEL_14: @@ -1488,69 +1483,98 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu r_type, r_format, r_field, r_pcrel); break; + /* Handle all basic type 6 relocations. */ case R_HPPA_UNWIND_ENTRY: case R_HPPA_UNWIND_ENTRIES: hppa_elf_relocate_unwind_table (abfd, input_section, data, addr, symbol_in, sym_value, r_addend, r_type, r_format, r_field, r_pcrel); - return (bfd_reloc_ok); - - case R_HPPA_PUSH_CONST: /* push Addend - - */ - case R_HPPA_PUSH_PC: /* push PC + Addend - - */ - case R_HPPA_PUSH_SYM: /* push Symbol + Addend - - */ - case R_HPPA_PUSH_GOTOFF: /* push Symbol - GOT + Addend - - */ - case R_HPPA_PUSH_ABS_CALL: /* push Symbol + Addend - - */ - case R_HPPA_PUSH_PCREL_CALL: /* push Symbol - PC + Addend - - */ - case R_HPPA_PUSH_PLABEL: /* [TBD] - - */ - case R_HPPA_MAX: /* pop A and B, push max(B,A) - - */ - case R_HPPA_MIN: /* pop A and B, push min(B,A) - - */ - case R_HPPA_ADD: /* pop A and B, push B + A - - */ - case R_HPPA_SUB: /* pop A and B, push B - A - - */ - case R_HPPA_MULT: /* pop A and B, push B * A - - */ - case R_HPPA_DIV: /* pop A and B, push B / A - - */ - case R_HPPA_MOD: /* pop A and B, push B % A - - */ - case R_HPPA_AND: /* pop A and B, push B & A - - */ - case R_HPPA_OR: /* pop A and B, push B | A - - */ - case R_HPPA_XOR: /* pop A and B, push B ^ A - - */ - case R_HPPA_NOT: /* pop A, push ~A - - */ - case R_HPPA_LSHIFT: /* pop A, push A << Addend - - */ - case R_HPPA_ARITH_RSHIFT: /* pop A, push A >> Addend - - */ - case R_HPPA_LOGIC_RSHIFT: /* pop A, push A >> Addend - - */ - case R_HPPA_EXPR_F: /* pop A, push A + Addend L - */ - case R_HPPA_EXPR_L: /* pop A, push L(A,Addend) L - */ - case R_HPPA_EXPR_R: /* pop A, push R(A,Addend) R - */ - case R_HPPA_EXPR_LS: /* pop A, push LS(A,Addend) LS - */ - case R_HPPA_EXPR_RS: /* pop A, push RS(A,Addend) RS - */ - case R_HPPA_EXPR_LD: /* pop A, push LD(A,Addend) LD - */ - case R_HPPA_EXPR_RD: /* pop A, push RD(A,Addend) RD - */ - case R_HPPA_EXPR_LR: /* pop A, push LR(A,Addend) LR - */ - case R_HPPA_EXPR_RR: /* pop A, push RR(A,Addend) RR - */ - - case R_HPPA_EXPR_32: /* pop - 32 */ - case R_HPPA_EXPR_21: /* pop - 21 */ - case R_HPPA_EXPR_11: /* pop - 11 */ - case R_HPPA_EXPR_14: /* pop - 14 */ - case R_HPPA_EXPR_17: /* pop - 17 */ - case R_HPPA_EXPR_12: /* pop - 12 */ + return bfd_reloc_ok; + + /* Handle the stack operations and similar braindamage. */ + case R_HPPA_PUSH_CONST: + case R_HPPA_PUSH_PC: + case R_HPPA_PUSH_SYM: + case R_HPPA_PUSH_GOTOFF: + case R_HPPA_PUSH_ABS_CALL: + case R_HPPA_PUSH_PCREL_CALL: + case R_HPPA_PUSH_PLABEL: + case R_HPPA_MAX: + case R_HPPA_MIN: + case R_HPPA_ADD: + case R_HPPA_SUB: + case R_HPPA_MULT: + case R_HPPA_DIV: + case R_HPPA_MOD: + case R_HPPA_AND: + case R_HPPA_OR: + case R_HPPA_XOR: + case R_HPPA_NOT: + case R_HPPA_LSHIFT: + case R_HPPA_ARITH_RSHIFT: + case R_HPPA_LOGIC_RSHIFT: + case R_HPPA_EXPR_F: + case R_HPPA_EXPR_L: + case R_HPPA_EXPR_R: + case R_HPPA_EXPR_LS: + case R_HPPA_EXPR_RS: + case R_HPPA_EXPR_LD: + case R_HPPA_EXPR_RD: + case R_HPPA_EXPR_LR: + case R_HPPA_EXPR_RR: + case R_HPPA_EXPR_32: + case R_HPPA_EXPR_21: + case R_HPPA_EXPR_11: + case R_HPPA_EXPR_14: + case R_HPPA_EXPR_17: + case R_HPPA_EXPR_12: fprintf (stderr, "Relocation problem: "); fprintf (stderr, "Unimplemented reloc type %d, in module %s\n", r_type, abfd->filename); - return (bfd_reloc_notsupported); + return bfd_reloc_notsupported; + + /* This is a linker internal relocation. */ case R_HPPA_STUB_CALL_17: - /* yes, a branch to a long branch stub. Change instruction to a BLE */ - /* or BLE,N */ - if ( insn & 2 ) + /* This relocation is for a branch to a long branch stub. + Change instruction to a BLE,N. It may also be necessary + to change interchange the branch and its delay slot. + The original instruction stream is + + bl <foo>,r ; call foo using register r as + ; the return pointer + XXX ; delay slot instruction + + The new instruction stream will be: + + XXX ; delay slot instruction + ble <foo_stub> ; call the long call stub for foo + ; using r31 as the return pointer + + This braindamage is necessary because the compiler may put + an instruction which uses %r31 in the delay slot of the original + call. By changing the call instruction from a "bl" to a "ble" + %r31 gets clobbered before the delay slot executes. + + We do not interchange the branch and delay slot if the delay + slot was already nullified, or if the instruction in the delay + slot modifies the return pointer to avoid an unconditional + jump after the call returns (GCC optimization). */ + + if (insn & 2) insn = BLE_N_XXX_0_0; else { unsigned long old_delay_slot_insn = bfd_get_32 (abfd, hit_data + 4); unsigned rtn_reg = (insn & 0x03e00000) >> 21; - if (get_opcode(old_delay_slot_insn) == LDO) + if (get_opcode (old_delay_slot_insn) == LDO) { unsigned ldo_src_reg = (old_delay_slot_insn & 0x03e00000) >> 21; unsigned ldo_target_reg = (old_delay_slot_insn & 0x001f0000) >> 16; + /* If the target of the LDO is the same as the return + register then there is no reordering. We can leave the + instuction as a non-nullified BLE in this case. */ if (ldo_target_reg == rtn_reg) { unsigned long new_delay_slot_insn = old_delay_slot_insn; @@ -1558,31 +1582,80 @@ DEFUN (hppa_elf_reloc, (abfd, reloc_entry, symbol_in, data, input_section, outpu BFD_ASSERT(ldo_src_reg == ldo_target_reg); new_delay_slot_insn &= 0xfc00ffff; new_delay_slot_insn |= ((31 << 21) | (31 << 16)); - bfd_put_32(abfd, new_delay_slot_insn, hit_data + 4); + bfd_put_32 (abfd, new_delay_slot_insn, hit_data + 4); + insn = BLE_XXX_0_0; + bfd_put_32 (abfd, insn, hit_data); + r_type = R_HPPA_ABS_CALL_17; + r_pcrel = 0; + insn = hppa_elf_relocate_insn (abfd, input_section, insn, + addr, symbol_in, sym_value, + r_addend, r_type, r_format, + r_field, r_pcrel); + bfd_put_32 (abfd, insn, hit_data + 4); + return bfd_reloc_ok; + } + else + { + /* Check to see if the delay slot instruction has a + relocation. If so, we need to change the address + field of it, because the instruction it relocates + is going to be moved. */ + arelent * next_reloc_entry = reloc_entry+1; + + if (next_reloc_entry->address == reloc_entry->address + 4) + next_reloc_entry->address -= 4; + + insn = old_delay_slot_insn; + bfd_put_32 (abfd, insn, hit_data); + insn = BLE_N_XXX_0_0; + bfd_put_32 (abfd, insn, hit_data + 4); + r_type = R_HPPA_ABS_CALL_17; + r_pcrel = 0; + insn = hppa_elf_relocate_insn (abfd, input_section, insn, + addr + 4, symbol_in, + sym_value, r_addend, r_type, + r_format, r_field, r_pcrel); + bfd_put_32 (abfd, insn, hit_data + 4); + return bfd_reloc_ok; } } - insn = BLE_XXX_0_0; + else + { + /* Check to see if the delay slot instruction has a + relocation. If so, we need to change its address + field because the instruction it relocates is going + to be moved. */ + arelent * next_reloc_entry = reloc_entry+1; + + if (next_reloc_entry->address == reloc_entry->address + 4) + next_reloc_entry->address -= 4; + + insn = old_delay_slot_insn; + bfd_put_32 (abfd, insn, hit_data); + insn = BLE_N_XXX_0_0; + bfd_put_32 (abfd, insn, hit_data + 4); + r_type = R_HPPA_ABS_CALL_17; + r_pcrel = 0; + insn = hppa_elf_relocate_insn (abfd, input_section, insn, + addr + 4, symbol_in, sym_value, + r_addend, r_type, r_format, + r_field, r_pcrel); + bfd_put_32 (abfd, insn, hit_data + 4); + return bfd_reloc_ok; + } } - bfd_put_32 (abfd, insn, hit_data); - r_type = R_HPPA_ABS_CALL_17; - r_pcrel = 0; - insn = hppa_elf_relocate_insn (abfd, input_section, insn, addr, - symbol_in, sym_value, r_addend, - r_type, r_format, r_field, r_pcrel); break; default: fprintf (stderr, "Relocation problem : "); fprintf (stderr, "Unrecognized reloc type %d, in module %s\n", r_type, abfd->filename); - return (bfd_reloc_dangerous); + return bfd_reloc_dangerous; } - /* update the instruction word */ + /* Update the instruction word. */ bfd_put_32 (abfd, insn, hit_data); - return (bfd_reloc_ok); - } static const reloc_howto_type * @@ -2003,15 +2076,18 @@ type_of_mismatch (caller_bits, callee_bits, type) #define EXTRACT_ARBITS(ar,which) ((ar) >> (8-(which*2))) & 3 #define NEW_INSTRUCTION(entry,insn) \ +{ \ *((entry)->stub_desc->stub_secp)++ = (insn); \ (entry)->stub_desc->real_size += sizeof(int); \ (entry)->size += sizeof(int); \ bfd_set_section_size((entry)->stub_desc->this_bfd, \ (entry)->stub_desc->stub_sec, \ - (entry)->stub_desc->real_size); + (entry)->stub_desc->real_size); \ +} #define CURRENT_STUB_OFFSET(entry) \ - ((int)(entry)->stub_desc->stub_secp - (int)(entry)->stub_desc->stub_contents - 4) + ((int)(entry)->stub_desc->stub_secp \ + - (int)(entry)->stub_desc->stub_contents - 4) static boolean stubs_finished = false; @@ -2198,11 +2274,14 @@ elf32_hppa_reloc_type type; } asymbol * -hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) +hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, + stub_types, rtn_adjust, data) bfd *abfd; bfd *output_bfd; arelent *reloc_entry; int stub_types[5]; + int rtn_adjust; + unsigned *data; { asection *stub_sec = bfd_get_section_by_name (abfd, ".hppa_linker_stubs"); elf32_hppa_stub_description *stub_desc = find_stubs (abfd, stub_sec); @@ -2212,27 +2291,45 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) int i; char stub_sym_name[128]; elf32_hppa_stub_name_list *stub_entry; + unsigned insn = data[0]; + + /* Perform some additional checks on whether we should really do the + return adjustment. For example, if the instruction is nullified + or if the delay slot contains an instruction that modifies the return + pointer, then the branch instructions should not be rearranged + (rtn_adjust is false). */ + if (insn & 2 || insn == 0) + rtn_adjust = false; + else + { + unsigned delay_insn = data[1]; + if (get_opcode (delay_insn) == LDO + && (((insn & 0x03e00000) >> 21) == ((delay_insn & 0x001f0000) >> 16))) + rtn_adjust = false; + } + + /* See if the proper stub entry has already been made. */ if (!stub_sec) { BFD_ASSERT (stub_desc == NULL); stub_sec = bfd_make_section (abfd, ".hppa_linker_stubs"); bfd_set_section_flags (abfd, stub_sec, - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_READONLY); + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_RELOC | SEC_CODE | SEC_READONLY); stub_sec->output_section = output_text_section->output_section; stub_sec->output_offset = 0; bfd_set_section_alignment (abfd, stub_sec, 2); stub_desc = new_stub (abfd, stub_sec); } - /* make sure we have a stub descriptor structure */ - + /* Make the stub if we did not find one already. */ if (!stub_desc) stub_desc = new_stub (abfd, stub_sec); - /* allocate some space to write the stub */ - + /* Allocate space to write the stub. + FIXME. Why using realloc?!? */ if (!stub_desc->stub_contents) { stub_desc->allocated_size = STUB_BUFFER_INCR; @@ -2243,55 +2340,65 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) stub_desc->allocated_size = stub_desc->allocated_size + STUB_BUFFER_INCR; stub_desc->stub_contents = (char *) realloc (stub_desc->stub_contents, stub_desc->allocated_size); - if (stub_desc->stub_contents == NULL) - abort (); } - stub_desc->stub_secp = (int *) (stub_desc->stub_contents + stub_desc->real_size); + stub_desc->stub_secp + = (int *) (stub_desc->stub_contents + stub_desc->real_size); sprintf (stub_sym_name, - "_stub_%s_%02d_%02d_%02d_%02d_%02d", + "_stub_%s_%02d_%02d_%02d_%02d_%02d_%s", reloc_entry->sym_ptr_ptr[0]->name, - stub_types[0], stub_types[1], stub_types[2], stub_types[3], stub_types[4]); - stub_entry = find_stub_by_name(abfd, stub_sec, stub_sym_name); + stub_types[0], stub_types[1], stub_types[2], + stub_types[3], stub_types[4], + rtn_adjust ? "RA" : ""); + stub_entry = find_stub_by_name (abfd, stub_sec, stub_sym_name); if (stub_entry) { stub_sym = stub_entry->sym; - /* redirect the original relocation from the old symbol (a function) */ - /* to the stub (the stub calls the function). */ - /* XXX do we need to change the relocation type? */ - reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *)); + /* Redirect the original relocation from the old symbol (a function) + to the stub (the stub calls the function). Should we need to + change the relocation type? */ + reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, + sizeof (asymbol *)); reloc_entry->sym_ptr_ptr[0] = stub_sym; + if (reloc_entry->howto->type != R_HPPA_PLABEL_32 + && (get_opcode(insn) == BLE || get_opcode (insn) == BE)) + reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17); } else { - /* Stub does not already exist. Create a new stub. */ - /* Create a new symbol to point to this stub */ + /* Create a new symbol to point to this stub. */ stub_sym = bfd_make_empty_symbol (abfd); stub_sym->name = bfd_zalloc (abfd, strlen (stub_sym_name) + 1); strcpy ((char *) stub_sym->name, stub_sym_name); - stub_sym->value = (int) stub_desc->stub_secp - (int) stub_desc->stub_contents; + stub_sym->value + = (int) stub_desc->stub_secp - (int) stub_desc->stub_contents; stub_sym->section = stub_sec; stub_sym->flags = BSF_LOCAL | BSF_FUNCTION; - stub_entry = add_stub_by_name(abfd, stub_sec, stub_sym); + stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym); - /* redirect the original relocation from the old symbol (a function) */ - /* to the stub (the stub calls the function). */ - /* XXX do we need to change the relocation type? */ - reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *)); + /* Redirect the original relocation from the old symbol (a function) + to the stub (the stub calls the function). Change the type of + relocation to be the internal use only stub R_HPPA_STUB_CALL_17. */ + reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, + sizeof (asymbol *)); reloc_entry->sym_ptr_ptr[0] = stub_sym; + if (reloc_entry->howto->type != R_HPPA_PLABEL_32 + && (get_opcode (insn) == BLE || get_opcode (insn) == BE)) + reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17); - /* generate the beginning common section for all stubs */ + /* Generate common code for all stubs. */ + NEW_INSTRUCTION (stub_entry, LDSID_31_1); + NEW_INSTRUCTION (stub_entry, MTSP_1_SR0); NEW_INSTRUCTION (stub_entry, ADDI_8_SP); - /* generate the code to move the arguments around */ + /* Generate code to move the arguments around. */ for (i = ARG0; i < ARG3; i++) { if (stub_types[i] != NO_ARG_RELOC) { - /* A stub is needed */ switch (stub_types[i]) { case R_TO_FR: @@ -2320,12 +2427,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) switch (i) { case ARG0: - NEW_INSTRUCTION(stub_entry, STWS_ARG0_M4SP); - NEW_INSTRUCTION(stub_entry, STWS_ARG1_M8SP); - NEW_INSTRUCTION(stub_entry, FLDDS_M8SP_FARG1); + NEW_INSTRUCTION (stub_entry, STWS_ARG0_M4SP); + NEW_INSTRUCTION (stub_entry, STWS_ARG1_M8SP); + NEW_INSTRUCTION (stub_entry, FLDDS_M8SP_FARG1); break; default: - AR_WARN(stub_types[i],i); + AR_WARN (stub_types[i],i); break; } continue; @@ -2334,12 +2441,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) switch (i) { case ARG2: - NEW_INSTRUCTION(stub_entry, STWS_ARG2_M4SP); - NEW_INSTRUCTION(stub_entry, STWS_ARG3_M8SP); - NEW_INSTRUCTION(stub_entry, FLDDS_M8SP_FARG3); + NEW_INSTRUCTION (stub_entry, STWS_ARG2_M4SP); + NEW_INSTRUCTION (stub_entry, STWS_ARG3_M8SP); + NEW_INSTRUCTION (stub_entry, FLDDS_M8SP_FARG3); break; default: - AR_WARN(stub_types[i],i); + AR_WARN (stub_types[i],i); break; } continue; @@ -2370,12 +2477,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) switch (i) { case ARG0: - NEW_INSTRUCTION(stub_entry, FSTDS_FARG1_M8SP); - NEW_INSTRUCTION(stub_entry, LDWS_M4SP_ARG0); - NEW_INSTRUCTION(stub_entry, LDWS_M8SP_ARG1); + NEW_INSTRUCTION (stub_entry, FSTDS_FARG1_M8SP); + NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG0); + NEW_INSTRUCTION (stub_entry, LDWS_M8SP_ARG1); break; default: - AR_WARN(stub_types[i],i); + AR_WARN (stub_types[i],i); break; } continue; @@ -2384,12 +2491,12 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) switch (i) { case ARG2: - NEW_INSTRUCTION(stub_entry, FSTDS_FARG3_M8SP); - NEW_INSTRUCTION(stub_entry, LDWS_M4SP_ARG2); - NEW_INSTRUCTION(stub_entry, LDWS_M8SP_ARG3); + NEW_INSTRUCTION (stub_entry, FSTDS_FARG3_M8SP); + NEW_INSTRUCTION (stub_entry, LDWS_M4SP_ARG2); + NEW_INSTRUCTION (stub_entry, LDWS_M8SP_ARG3); break; default: - AR_WARN(stub_types[i],i); + AR_WARN (stub_types[i],i); break; } continue; @@ -2398,37 +2505,40 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) } } - NEW_INSTRUCTION (stub_entry, ADDI_M8_SP); + NEW_INSTRUCTION (stub_entry, ADDI_M8_SP_SP); + + /* Adjust the return address if necessary. */ + if (rtn_adjust) + { + NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP); + } - /* generate the branch to the target routine */ - NEW_INSTRUCTION (stub_entry, STW_RP_M8SP); /* First, save the return address */ + /* Save the return address. */ + NEW_INSTRUCTION (stub_entry, STW_RP_M8SP); - /* Branch to the target function. */ - /* (Make it a long call, so we do not */ - /* have to worry about generating a */ - /* long call stub.) */ - NEW_INSTRUCTION(stub_entry, LDIL_XXX_31); + /* Long branch to the target function. */ + NEW_INSTRUCTION (stub_entry, LDIL_XXX_31); hppa_elf_stub_reloc (stub_entry->stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_L21); - NEW_INSTRUCTION(stub_entry,BLE_XXX_0_31); + NEW_INSTRUCTION (stub_entry, BLE_XXX_0_31); hppa_elf_stub_reloc (stub_entry->stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_ABS_CALL_R17); - NEW_INSTRUCTION(stub_entry,COPY_31_2); - - /* generate the code to move the return value around */ + NEW_INSTRUCTION (stub_entry, COPY_31_2); - NEW_INSTRUCTION (stub_entry, LDW_M8SP_RP); /* restore return address */ + + /* Restore the return address. */ + NEW_INSTRUCTION (stub_entry, LDW_M8SP_RP); + /* Generate the code to move the return value around. */ i = RETVAL; if (stub_types[i] != NO_ARG_RELOC) { - /* A stub is needed */ switch (stub_types[i]) { case R_TO_FR: @@ -2442,10 +2552,6 @@ hppa_elf_build_arg_reloc_stub (abfd, output_bfd, reloc_entry, stub_types) break; } } - - /* generate the ending common section for all stubs */ - - /* XXX: can we assume this is a save return? */ NEW_INSTRUCTION (stub_entry, BV_N_0_RP); } @@ -2587,45 +2693,49 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data) int milli = false; int dyncall = false; elf32_hppa_stub_name_list *stub_entry; + int rtn_adjust = true; + int rtn_reg; + unsigned insn; + /* Create the stub section if it does not already exist. */ if (!stub_sec) { BFD_ASSERT (stub_desc == NULL); stub_sec = bfd_make_section (abfd, ".hppa_linker_stubs"); bfd_set_section_flags (abfd, stub_sec, - SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_CODE | SEC_READONLY); + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_RELOC | SEC_CODE | SEC_READONLY); stub_sec->output_section = output_text_section->output_section; stub_sec->output_offset = 0; - /* set up the ELF section header for this new section. */ - /* This is basically the same processing as elf_make_sections() */ - /* (elf_make_sections() is static so it is not accessible from */ - /* here.) */ + /* Set up the ELF section header for this new section. This + is basically the same processing as elf_make_sections(). + elf_make_sections is static and therefore not accessable + here. */ { Elf_Internal_Shdr *this_hdr; this_hdr = &elf_section_data (stub_sec)->this_hdr; - + + /* Set the sizes of this section. The contents have already + been set up ?!? */ this_hdr->sh_addr = stub_sec->vma; this_hdr->sh_size = stub_sec->_raw_size; - /* contents already set by elf_set_section_contents */ - + + /* Set appropriate flags for sections with relocations. */ if (stub_sec->flags & SEC_RELOC) { - /* emit a reloc section, and thus strtab and symtab... */ Elf_Internal_Shdr *rela_hdr; int use_rela_p = get_elf_backend_data (abfd)->use_rela_p; - + rela_hdr = &elf_section_data (stub_sec)->rel_hdr; - - /* orelocation has the data, reloc_count has the count... */ + if (use_rela_p) { rela_hdr->sh_type = SHT_RELA; rela_hdr->sh_entsize = sizeof (Elf32_External_Rela); } else - /* REL relocations */ { rela_hdr->sh_type = SHT_REL; rela_hdr->sh_entsize = sizeof (Elf32_External_Rel); @@ -2636,30 +2746,30 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data) rela_hdr->sh_addralign = 0; rela_hdr->size = 0; } + if (stub_sec->flags & SEC_ALLOC) { this_hdr->sh_flags |= SHF_ALLOC; - if (stub_sec->flags & SEC_LOAD) - { - /* @@ Do something with sh_type? */ - } + /* FIXME. If SEC_LOAD is true should we do something with + with sh_type? */ } + if (!(stub_sec->flags & SEC_READONLY)) this_hdr->sh_flags |= SHF_WRITE; - + if (stub_sec->flags & SEC_CODE) this_hdr->sh_flags |= SHF_EXECINSTR; } - + bfd_set_section_alignment (abfd, stub_sec, 2); stub_desc = new_stub (abfd, stub_sec); } - + if (!stub_desc) stub_desc = new_stub (abfd, stub_sec); - - /* allocate some space to write the stub */ - + + /* Allocate memory to contain the stub. FIXME. Why isn't this using + the BFD memory allocation routines? */ if (!stub_desc->stub_contents) { stub_desc->allocated_size = STUB_BUFFER_INCR; @@ -2669,121 +2779,166 @@ hppa_elf_build_long_branch_stub (abfd, output_bfd, reloc_entry, symbol, data) { stub_desc->allocated_size = stub_desc->allocated_size + STUB_BUFFER_INCR; stub_desc->stub_contents = (char *) realloc (stub_desc->stub_contents, - stub_desc->allocated_size); + stub_desc->allocated_size); } - - stub_desc->stub_secp = (int *) (stub_desc->stub_contents + stub_desc->real_size); - + + stub_desc->stub_secp + = (int *) (stub_desc->stub_contents + stub_desc->real_size); + + /* Is this a millicode call? If so, the return address + comes in on r31 rather than r2 (rp) so a slightly + different code sequence is needed. */ + + insn = data[0]; + rtn_reg = (insn & 0x03e00000) >> 21; + if (rtn_reg == 31) + milli = true; + + if (strcmp (symbol->name, "$$dyncall") == 0) + dyncall = true; + + /* Check to see if we modify the return pointer + in the delay slot of the branch. */ + { + unsigned delay_insn = data[1]; + + /* If we nullify the delay slot, or if the delay slot contains an + instruction that modifies the return pointer, then no additional + modification of the return pointer is necessary. */ + if (insn & 2 || insn == 0) + rtn_adjust = false; + else + { + if (get_opcode (delay_insn) == LDO + && (((delay_insn & 0x001f0000) >> 16) == rtn_reg)) + rtn_adjust = false; + } + } + sprintf (stub_sym_name, - "_lb_stub_%s", reloc_entry->sym_ptr_ptr[0]->name); + "_lb_stub_%s_%s", reloc_entry->sym_ptr_ptr[0]->name, + rtn_adjust ? "RA" : ""); stub_entry = find_stub_by_name(abfd, stub_sec, stub_sym_name); + /* If a copy of this stub already exists re-use it. */ if (stub_entry) { stub_sym = stub_entry->sym; - /* redirect the original relocation from the old symbol (a function) */ - /* to the stub (the stub calls the function). */ - /* XXX do we need to change the relocation type? */ - reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *)); + + /* Change symbol associated with the original relocation to point + to the stub. + + FIXME. Is there a need to change the relocation type too? */ + reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, + sizeof (asymbol *)); reloc_entry->sym_ptr_ptr[0] = stub_sym; reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17); } else { - /* Stub does not already exist. Create a new stub. */ - /* create a symbol to point to this stub */ + /* We will need to allocate a new stub. */ stub_sym = bfd_make_empty_symbol (abfd); stub_sym->name = bfd_zalloc (abfd, strlen (stub_sym_name) + 1); strcpy ((char *) stub_sym->name, stub_sym_name); - stub_sym->value = (int) stub_desc->stub_secp - (int) stub_desc->stub_contents; + stub_sym->value + = (int) stub_desc->stub_secp - (int) stub_desc->stub_contents; stub_sym->section = stub_sec; stub_sym->flags = BSF_LOCAL | BSF_FUNCTION; - stub_entry = add_stub_by_name(abfd, stub_sec, stub_sym); + stub_entry = add_stub_by_name (abfd, stub_sec, stub_sym); + + /* Change symbol associated with the original relocation to point + to the stub. - /* redirect the original relocation from the old symbol (a function) */ - /* to the stub (the stub calls the function). */ - /* XXX do we need to change the relocation type? */ - reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, sizeof (asymbol *)); + FIXME. Is there a need to change the relocation type too? */ + reloc_entry->sym_ptr_ptr = (asymbol **) bfd_zalloc (stub_desc->this_bfd, + sizeof (asymbol *)); reloc_entry->sym_ptr_ptr[0] = stub_sym; reloc_entry->howto = bfd_reloc_type_lookup (abfd, R_HPPA_STUB_CALL_17); - - /* Build the stub */ - - /* A millicode call? */ - /* If so, the return address comes in on r31 rather than r2 (rp) so a */ - /* slightly different code sequence is needed. */ - if ( ((*data & 0x03e00000) >> 21) == 31 ) - milli = true; - - if ( strcmp(symbol->name,"$$dyncall") == 0 ) - dyncall = true; - + + /* Build the stub. */ + /* 1. initialization for the call. */ - - NEW_INSTRUCTION(stub_entry, LDSID_31_1); - NEW_INSTRUCTION(stub_entry, MTSP_1_SR0); - - if ( !dyncall ) + NEW_INSTRUCTION (stub_entry, LDSID_31_1); + NEW_INSTRUCTION (stub_entry, MTSP_1_SR0); + + if (!dyncall) { - if ( !milli ) + if (!milli) { - NEW_INSTRUCTION(stub_entry, COPY_31_2); + if (rtn_adjust) + { + NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP); + } + else + { + NEW_INSTRUCTION (stub_entry, COPY_31_2); + } } else { - NEW_INSTRUCTION(stub_entry, COPY_31_1); + if (rtn_adjust) + { + NEW_INSTRUCTION (stub_entry, ADDI_M4_31_1); + } + else + { + NEW_INSTRUCTION (stub_entry, COPY_31_1); + } } - - NEW_INSTRUCTION(stub_entry, LDIL_XXX_31); + + NEW_INSTRUCTION (stub_entry, LDIL_XXX_31); hppa_elf_stub_reloc (stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_L21); /* 2. Make the call. */ - - if ( !milli ) + if (!milli) { - NEW_INSTRUCTION(stub_entry,BE_N_XXX_0_31); + NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31); hppa_elf_stub_reloc (stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_ABS_CALL_R17); } else { - NEW_INSTRUCTION(stub_entry,BE_XXX_0_31); + NEW_INSTRUCTION (stub_entry, BE_XXX_0_31); hppa_elf_stub_reloc (stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_ABS_CALL_R17); - NEW_INSTRUCTION(stub_entry, COPY_1_31); + NEW_INSTRUCTION (stub_entry, COPY_1_31); } - /* 3. Branch back to the original location. */ - /* (for non-millicode calls, accomplished with the COPY_31_2 instruction) */ - /* (for millicode calls, return location is already in r2) */ } else { - NEW_INSTRUCTION(stub_entry, LDIL_XXX_31); + /* 3. Branch back to the original location. + (For non-millicode calls, this is accomplished with the + COPY_31_2 instruction. For millicode calls, the return + location is already in r2.) */ + if (rtn_adjust) + { + NEW_INSTRUCTION (stub_entry, ADDI_M4_31_RP); + } + NEW_INSTRUCTION (stub_entry, LDIL_XXX_31); hppa_elf_stub_reloc (stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_L21); - - NEW_INSTRUCTION(stub_entry,BE_N_XXX_0_31); + + NEW_INSTRUCTION (stub_entry, BE_N_XXX_0_31); hppa_elf_stub_reloc (stub_desc, - abfd, /* the output bfd */ - target_sym, /* the target symbol */ - CURRENT_STUB_OFFSET(stub_entry), /* offset in stub buffer */ + abfd, + target_sym, + CURRENT_STUB_OFFSET (stub_entry), R_HPPA_ABS_CALL_R17); } } - return stub_sym; } @@ -2819,86 +2974,11 @@ hppa_elf_long_branch_needed_p (abfd, asec, reloc_entry, symbol, insn) return 0; } -asymbol * -hppa_elf_stub_check (abfd, output_bfd, input_section, reloc_entry, symbol, hit_data) - bfd *abfd; - bfd *output_bfd; - asection *input_section; - arelent *reloc_entry; - asymbol *symbol; - bfd_byte *hit_data; -{ - int stub_types[5]; - - switch (reloc_entry->howto->type) - { - case R_HPPA_ABS_CALL_11: /* Symbol + Addend 11 */ - case R_HPPA_ABS_CALL_14: /* Symbol + Addend 14 */ - case R_HPPA_ABS_CALL_17: /* Symbol + Addend 17 */ - case R_HPPA_ABS_CALL_L21: /* L (Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_R11: /* R (Symbol, Addend) 11 */ - case R_HPPA_ABS_CALL_R14: /* R (Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_R17: /* R (Symbol, Addend) 17 */ - case R_HPPA_ABS_CALL_LS21: /* LS(Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_RS11: /* RS(Symbol, Addend) 11 */ - case R_HPPA_ABS_CALL_RS14: /* RS(Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_RS17: /* RS(Symbol, Addend) 17 */ - case R_HPPA_ABS_CALL_LD21: /* LD(Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_RD11: /* RD(Symbol, Addend) 11 */ - case R_HPPA_ABS_CALL_RD14: /* RD(Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_RD17: /* RD(Symbol, Addend) 17 */ - case R_HPPA_ABS_CALL_LR21: /* LR(Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_RR14: /* RR(Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_RR17: /* RR(Symbol, Addend) 17 */ - - case R_HPPA_PCREL_CALL_11: /* Symbol - PC + Addend 11 */ - case R_HPPA_PCREL_CALL_14: /* Symbol - PC + Addend 14 */ - case R_HPPA_PCREL_CALL_17: /* Symbol - PC + Addend 17 */ - case R_HPPA_PCREL_CALL_12: /* Symbol - PC + Addend 12 */ - case R_HPPA_PCREL_CALL_L21: /* L (Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_R11: /* R (Symbol - PC, Addend) 11 */ - case R_HPPA_PCREL_CALL_R14: /* R (Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_R17: /* R (Symbol - PC, Addend) 17 */ - case R_HPPA_PCREL_CALL_LS21: /* LS(Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_RS11: /* RS(Symbol - PC, Addend) 11 */ - case R_HPPA_PCREL_CALL_RS14: /* RS(Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_RS17: /* RS(Symbol - PC, Addend) 17 */ - case R_HPPA_PCREL_CALL_LD21: /* LD(Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_RD11: /* RD(Symbol - PC, Addend) 11 */ - case R_HPPA_PCREL_CALL_RD14: /* RD(Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_RD17: /* RD(Symbol - PC, Addend) 17 */ - case R_HPPA_PCREL_CALL_LR21: /* LR(Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_RR14: /* RR(Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_RR17: /* RR(Symbol - PC, Addend) 17 */ - { - symext_entryS caller_ar = (symext_entryS) HPPA_R_ARG_RELOC (reloc_entry->addend); - if (hppa_elf_arg_reloc_needed_p (abfd, reloc_entry, stub_types, caller_ar)) - { - /* generate a stub */ - return hppa_elf_build_arg_reloc_stub (abfd, output_bfd, - reloc_entry, stub_types); - } - if (hppa_elf_long_branch_needed_p (abfd, input_section, reloc_entry, - symbol, *(unsigned *)hit_data)) - { - /* generate a stub */ - return hppa_elf_build_long_branch_stub (abfd, output_bfd, - reloc_entry, symbol, - (unsigned *)hit_data); - } - } - break; - - default: - break; - } - return reloc_entry->sym_ptr_ptr[0]; -} - #define STUB_SYM_BUFFER_INC 5 asymbol * -hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec, syms, new_sym_cnt) +hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec, + syms, new_sym_cnt) bfd *stub_bfd; bfd *abfd; bfd *output_bfd; @@ -2915,152 +2995,165 @@ hppa_look_for_stubs_in_section (stub_bfd, abfd, output_bfd, asec, syms, new_sym_ /* Relocations are in different places depending on whether this is an output section or an input section. Also, the relocations are in different forms. Sigh. Luckily, we have - bfd_canonicalize_reloc() to straighten this out for us. */ + bfd_canonicalize_reloc() to straighten this out for us . */ - /* if ( asec->orelocation || asec->relocation ) { */ if (asec->reloc_count > 0) { - arelent **reloc_vector = (arelent **) alloca (asec->reloc_count * (sizeof (arelent *) + 1)); + arelent **reloc_vector + = (arelent **) alloca (asec->reloc_count * (sizeof (arelent *) + 1)); bfd_canonicalize_reloc (abfd, asec, reloc_vector, syms); for (i = 0; i < asec->reloc_count; i++) { -#if 0 - arelent *rle; - - if ( asec->orelocation ) - rle = asec->orelocation[i]; - else - rle = asec->relocation+i; -#endif - arelent *rle = reloc_vector[i]; switch (rle->howto->type) { - case R_HPPA_ABS_CALL_11: /* Symbol + Addend 11 */ - case R_HPPA_ABS_CALL_14: /* Symbol + Addend 14 */ - case R_HPPA_ABS_CALL_17: /* Symbol + Addend 17 */ - case R_HPPA_ABS_CALL_L21: /* L (Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_R11: /* R (Symbol, Addend) 11 */ - case R_HPPA_ABS_CALL_R14: /* R (Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_R17: /* R (Symbol, Addend) 17 */ - case R_HPPA_ABS_CALL_LS21: /* LS(Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_RS11: /* RS(Symbol, Addend) 11 */ - case R_HPPA_ABS_CALL_RS14: /* RS(Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_RS17: /* RS(Symbol, Addend) 17 */ - case R_HPPA_ABS_CALL_LD21: /* LD(Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_RD11: /* RD(Symbol, Addend) 11 */ - case R_HPPA_ABS_CALL_RD14: /* RD(Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_RD17: /* RD(Symbol, Addend) 17 */ - case R_HPPA_ABS_CALL_LR21: /* LR(Symbol, Addend) 21 */ - case R_HPPA_ABS_CALL_RR14: /* RR(Symbol, Addend) 14 */ - case R_HPPA_ABS_CALL_RR17: /* RR(Symbol, Addend) 17 */ - - case R_HPPA_PCREL_CALL_11: /* Symbol - PC + Addend 11 */ - case R_HPPA_PCREL_CALL_14: /* Symbol - PC + Addend 14 */ - case R_HPPA_PCREL_CALL_17: /* Symbol - PC + Addend 17 */ - case R_HPPA_PCREL_CALL_12: /* Symbol - PC + Addend 12 */ - case R_HPPA_PCREL_CALL_L21: /* L (Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_R11: /* R (Symbol - PC, Addend) 11 */ - case R_HPPA_PCREL_CALL_R14: /* R (Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_R17: /* R (Symbol - PC, Addend) 17 */ - case R_HPPA_PCREL_CALL_LS21: /* LS(Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_RS11: /* RS(Symbol - PC, Addend) 11 */ - case R_HPPA_PCREL_CALL_RS14: /* RS(Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_RS17: /* RS(Symbol - PC, Addend) 17 */ - case R_HPPA_PCREL_CALL_LD21: /* LD(Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_RD11: /* RD(Symbol - PC, Addend) 11 */ - case R_HPPA_PCREL_CALL_RD14: /* RD(Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_RD17: /* RD(Symbol - PC, Addend) 17 */ - case R_HPPA_PCREL_CALL_LR21: /* LR(Symbol - PC, Addend) 21 */ - case R_HPPA_PCREL_CALL_RR14: /* RR(Symbol - PC, Addend) 14 */ - case R_HPPA_PCREL_CALL_RR17: /* RR(Symbol - PC, Addend) 17 */ + case R_HPPA_ABS_CALL_11: + case R_HPPA_ABS_CALL_14: + case R_HPPA_ABS_CALL_17: + case R_HPPA_ABS_CALL_L21: + case R_HPPA_ABS_CALL_R11: + case R_HPPA_ABS_CALL_R14: + case R_HPPA_ABS_CALL_R17: + case R_HPPA_ABS_CALL_LS21: + case R_HPPA_ABS_CALL_RS11: + case R_HPPA_ABS_CALL_RS14: + case R_HPPA_ABS_CALL_RS17: + case R_HPPA_ABS_CALL_LD21: + case R_HPPA_ABS_CALL_RD11: + case R_HPPA_ABS_CALL_RD14: + case R_HPPA_ABS_CALL_RD17: + case R_HPPA_ABS_CALL_LR21: + case R_HPPA_ABS_CALL_RR14: + case R_HPPA_ABS_CALL_RR17: + case R_HPPA_PCREL_CALL_11: + case R_HPPA_PCREL_CALL_14: + case R_HPPA_PCREL_CALL_17: + case R_HPPA_PCREL_CALL_12: + case R_HPPA_PCREL_CALL_L21: + case R_HPPA_PCREL_CALL_R11: + case R_HPPA_PCREL_CALL_R14: + case R_HPPA_PCREL_CALL_R17: + case R_HPPA_PCREL_CALL_LS21: + case R_HPPA_PCREL_CALL_RS11: + case R_HPPA_PCREL_CALL_RS14: + case R_HPPA_PCREL_CALL_RS17: + case R_HPPA_PCREL_CALL_LD21: + case R_HPPA_PCREL_CALL_RD11: + case R_HPPA_PCREL_CALL_RD14: + case R_HPPA_PCREL_CALL_RD17: + case R_HPPA_PCREL_CALL_LR21: + case R_HPPA_PCREL_CALL_RR14: + case R_HPPA_PCREL_CALL_RR17: { - symext_entryS caller_ar = (symext_entryS) HPPA_R_ARG_RELOC (rle->addend); + symext_entryS caller_ar + = (symext_entryS) HPPA_R_ARG_RELOC (rle->addend); + unsigned insn[2]; + + bfd_get_section_contents (abfd, asec, insn, rle->address, + sizeof(insn)); if (hppa_elf_arg_reloc_needed_p (abfd, rle, stub_types, caller_ar)) { - /* generate a stub */ - /* keep track of the new symbol */ + /* Generate a stub and keep track of the new symbol. */ asymbol *r; if (new_cnt == new_max) { new_max += STUB_SYM_BUFFER_INC; - new_syms = (asymbol *) realloc (new_syms, new_max * sizeof (asymbol)); + new_syms = (asymbol *) + realloc (new_syms, new_max * sizeof (asymbol)); } + + /* The rtn_adjust argument is true here because we + know that we have a branch and (with a few exceptions + detailed under the relocation code for relocation type + R_HPPA_STUB_CALL_17) it will be possible to perform + the code reorientation. */ r = hppa_elf_build_arg_reloc_stub (stub_bfd, output_bfd, - rle, stub_types); + rle, stub_types, + true, insn); new_syms[new_cnt++] = *r; } - /* We need to retrieve the section contents to check for - plabel stubs. */ - { - unsigned insn; - bfd_get_section_contents (abfd, asec, &insn, rle->address, - sizeof(insn)); - if (hppa_elf_long_branch_needed_p (abfd, asec, rle, - rle->sym_ptr_ptr[0], - insn)) - { - /* generate a stub */ - /* keep track of the new symbol */ - asymbol *r; + /* We need to retrieve the section contents to check for + long branch stubs. */ + if (hppa_elf_long_branch_needed_p (abfd, asec, rle, + rle->sym_ptr_ptr[0], + insn[0])) + { + /* Generate a stub and keep track of the new symbol. */ + asymbol *r; - if (new_cnt == new_max) - { - new_max += STUB_SYM_BUFFER_INC; - new_syms = (asymbol *) realloc (new_syms, (new_max * sizeof (asymbol))); - } - r = hppa_elf_build_long_branch_stub (stub_bfd, - output_bfd, - rle, - rle->sym_ptr_ptr[0], - &insn); - new_syms[new_cnt++] = *r; - } - } + if (new_cnt == new_max) + { + new_max += STUB_SYM_BUFFER_INC; + new_syms = (asymbol *) + realloc (new_syms, (new_max * sizeof (asymbol))); + } + r = hppa_elf_build_long_branch_stub (stub_bfd, output_bfd, + rle, + rle->sym_ptr_ptr[0], + insn); + new_syms[new_cnt++] = *r; + } } break; - /* Plabels are designed to allow code pointers to be - passed between spaces. These relocations correspond - to the P%, LP%, and RP% field selectors. */ - - case R_HPPA_PLABEL_32: /* F(Plabel(Symbol,Addend),0) 32 */ - case R_HPPA_PLABEL_11: /* F(Plabel(Symbol,Addend),0) 11 */ - case R_HPPA_PLABEL_14: /* F(Plabel(Symbol,Addend),0) 14 */ - case R_HPPA_PLABEL_L21: /* L(Plabel(Symbol,Addend),0) 21 */ - case R_HPPA_PLABEL_R11: /* R(Plabel(Symbol,Addend),0) 11 */ - case R_HPPA_PLABEL_R14: /* R(Plabel(Symbol,Addend),0) 14 */ - /* We need to retrieve the section contents to check for - long branch stubs. */ + case R_HPPA_PLABEL_32: + case R_HPPA_PLABEL_11: + case R_HPPA_PLABEL_14: + case R_HPPA_PLABEL_L21: + case R_HPPA_PLABEL_R11: + case R_HPPA_PLABEL_R14: { /* On a plabel relocation, assume the arguments of the - caller are set up in general registers. */ - /* 0x155 = ARGW0=CR,ARGW1=GR,ARGW2=GR,RETVAL=GR */ + caller are set up in general registers. + NOTE: 0x155 = ARGW0=CR,ARGW1=GR,ARGW2=GR,RETVAL=GR */ symext_entryS caller_ar = (symext_entryS) 0x155; + unsigned insn[2]; + + bfd_get_section_contents (abfd, asec, insn, rle->address, + sizeof(insn)); if (hppa_elf_arg_reloc_needed_p (abfd, rle, stub_types, caller_ar)) { - /* generate a plabel stub */ - /* keep track of the new symbol */ + /* Generate a plabel stub and keep track of the + new symbol. */ asymbol *r; + int rtn_adjust; if (new_cnt == new_max) { new_max += STUB_SYM_BUFFER_INC; - new_syms = (asymbol *) realloc (new_syms, - (new_max - * sizeof (asymbol))); + new_syms = (asymbol *) realloc (new_syms, new_max + * sizeof (asymbol)); } - r = hppa_elf_build_arg_reloc_stub (stub_bfd, - output_bfd, - rle, - stub_types); + + /* Determine whether a return adjustment + (see the relocation code for relocation type + R_HPPA_STUB_CALL_17) is possible. Basically, + determine whether we are looking at a branch or not. */ + + if (rle->howto->type == R_HPPA_PLABEL_32) + rtn_adjust = false; + else + { + switch (get_opcode(insn[0])) + { + case BLE: + case BE: + rtn_adjust = true; + break; + default: + rtn_adjust = false; + } + } + r = hppa_elf_build_arg_reloc_stub (stub_bfd, output_bfd, + rle, stub_types, + rtn_adjust, insn); new_syms[new_cnt++] = *r; } } @@ -3150,7 +3243,7 @@ hppa_elf_get_section_contents (abfd, section, location, offset, count) be generated. */ else if (strcmp (section->name, ".hppa_symextn") == 0) { - /* If there are no output sections, then read the contents of the + /* If there are no output sections, then read the contents of the symbol extension section from disk. */ if (section->output_section == NULL && abfd->direction == read_direction) |