From 46bc1bf6ba9884c991be5a82a64ccb6dac7206cf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 6 Apr 1993 00:53:41 +0000 Subject: [PATCH] These changes make shared library support work again on 386 COFF systems. * coffcode.h (styp_to_sec_flags): Set SEC_SHARED_LIBRARY for a STYP_NOLOAD | STYP_BSS section. Don't set SEC_NEVER_LOAD for a STYP_INFO section. (coff_compute_section_file_positions): Force vma and lma of _LIB section to be zero. (coff_set_section_contents): Count number of entries in new lma field, not in vma. * coffgen.c (make_a_section_from_file): Force lineno_count of SEC_SHARED_LIBRARY section to be zero, since it is non-zero on the SCO 3.2v4 shared library. * seclet.c (rel): Copy over any section with contents, not just loadable sections. * coff-mips.c (ecoff_make_empty_symbol): Zero out newly allocated symbol. --- bfd/ChangeLog | 16 +++++ bfd/coff-mips.c | 174 ++++++++++++++++++++++++++++++++---------------- bfd/seclet.c | 5 +- 3 files changed, 132 insertions(+), 63 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 05d2dd09734..bd62d19ebb1 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,21 @@ Mon Apr 5 12:07:12 1993 Ian Lance Taylor (ian@cygnus.com) + * coffcode.h (styp_to_sec_flags): Set SEC_SHARED_LIBRARY for a + STYP_NOLOAD | STYP_BSS section. Don't set SEC_NEVER_LOAD for a + STYP_INFO section. + (coff_compute_section_file_positions): Force vma and lma of _LIB + section to be zero. + (coff_set_section_contents): Count number of entries in new lma + field, not in vma. + * coffgen.c (make_a_section_from_file): Force lineno_count of + SEC_SHARED_LIBRARY section to be zero, since it is non-zero on the + SCO 3.2v4 shared library. + * seclet.c (rel): Copy over any section with contents, not just + loadable sections. + + * coff-mips.c (ecoff_make_empty_symbol): Zero out newly allocated + symbol. + * coff-i386.c (coff_i386_reloc): New function, to generate relocateable output correctly. (howto_table): Use coff_i386_reloc for all reloc types. diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c index 595c19b2bbe..114803977b2 100644 --- a/bfd/coff-mips.c +++ b/bfd/coff-mips.c @@ -59,12 +59,6 @@ typedef struct ecoff_symbol_struct macro is only ever applied to an asymbol. */ #define ecoffsymbol(asymbol) ((ecoff_symbol_type *) (&((asymbol)->the_bfd))) -/* This is a hack borrowed from coffcode.h; we need to save the index - of a symbol when we write it out so that can set the symbol index - correctly when we write out the relocs. */ -#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata) -#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx)) - /* The page boundary used to align sections in the executable file. */ #define PAGE_SIZE 0x2000 @@ -122,6 +116,12 @@ static bfd_reloc_status_type ecoff_refhi_reloc PARAMS ((bfd *abfd, PTR data, asection *section, bfd *output_bfd)); +static bfd_reloc_status_type ecoff_reflo_reloc PARAMS ((bfd *abfd, + arelent *reloc, + asymbol *symbol, + PTR data, + asection *section, + bfd *output_bfd)); static bfd_reloc_status_type ecoff_gprel_reloc PARAMS ((bfd *abfd, arelent *reloc, asymbol *symbol, @@ -264,7 +264,7 @@ ecoff_mkobject (abfd) bfd *abfd; { abfd->tdata.ecoff_obj_data = ((struct ecoff_tdata *) - bfd_zalloc (abfd, sizeof(ecoff_data_type))); + bfd_zalloc (abfd, sizeof (ecoff_data_type))); if (abfd->tdata.ecoff_obj_data == NULL) { bfd_error = no_memory; @@ -294,6 +294,7 @@ ecoff_mkobject_hook (abfd, filehdr, aouthdr) return NULL; ecoff = ecoff_data (abfd); + ecoff->gp_size = 8; ecoff->sym_filepos = internal_f->f_symptr; if (internal_a != (struct internal_aouthdr *) NULL) @@ -618,6 +619,7 @@ ecoff_make_empty_symbol (abfd) bfd_error = no_memory; return (asymbol *) NULL; } + memset (new, 0, sizeof *new); new->symbol.section = (asection *) NULL; new->fdr = (FDR *) NULL; new->local = false; @@ -648,7 +650,13 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext) case stLabel: case stProc: case stStaticProc: + break; case stNil: + if (MIPS_IS_STAB (ecoff_sym)) + { + asym->flags = BSF_DEBUGGING; + return; + } break; default: asym->flags = BSF_DEBUGGING; @@ -724,14 +732,10 @@ ecoff_set_symbol_info (abfd, ecoff_sym, asym, ext) asym->flags = BSF_DEBUGGING; break; case scCommon: - /* FIXME: We should take a -G argument, which gives the maximum - size of objects to be put in the small common section. Until - we do, we put objects of sizes up to 8 in the small common - section. The assembler should do this for us, but the native - assembler seems to get confused. */ - if (asym->value > 8) + if (asym->value > ecoff_data (abfd)->gp_size) { asym->section = &bfd_com_section; + asym->flags = 0; break; } /* Fall through. */ @@ -1491,10 +1495,11 @@ ecoff_swap_reloc_out (abfd, src, dst) /* ECOFF relocs are either against external symbols, or against sections. If we are producing relocateable output, and the reloc - is against an external symbol, the resulting reloc will also be - against the same symbol. In such a case, we don't want to change - anything about the way the reloc is handled, since it will all be - done at final link time. Rather than put special case code into + is against an external symbol, and nothing has given us any + additional addend, the resulting reloc will also be against the + same symbol. In such a case, we don't want to change anything + about the way the reloc is handled, since it will all be done at + final link time. Rather than put special case code into bfd_perform_relocation, all the reloc types use this howto function. It just short circuits the reloc if producing relocateable output against an external symbol. */ @@ -1514,7 +1519,8 @@ ecoff_generic_reloc (abfd, bfd *output_bfd; { if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0) + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1523,9 +1529,14 @@ ecoff_generic_reloc (abfd, return bfd_reloc_continue; } -/* Do a REFHI relocation. The next reloc must be the corresponding - REFLO. This has to be done in a function so that carry is handled - correctly. */ +/* Do a REFHI relocation. This has to be done in combination with a + REFLO reloc, because there is a carry from the REFLO to the REFHI. + Here we just save the information we need; we do the actual + relocation when we see the REFLO. ECOFF requires that the REFLO + immediately follow the REFHI, so this ought to work. */ + +static bfd_byte *ecoff_refhi_addr; +static bfd_vma ecoff_refhi_addend; static bfd_reloc_status_type ecoff_refhi_reloc (abfd, @@ -1542,16 +1553,13 @@ ecoff_refhi_reloc (abfd, bfd *output_bfd; { bfd_reloc_status_type ret; - arelent *rello; bfd_vma relocation; - unsigned long insn; - unsigned long val; - unsigned long vallo; /* If we're relocating, and this an external symbol, we don't want to change anything. */ if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0) + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1562,10 +1570,6 @@ ecoff_refhi_reloc (abfd, && output_bfd == (bfd *) NULL) ret = bfd_reloc_undefined; - rello = reloc_entry + 1; - BFD_ASSERT (rello->howto->type == ECOFF_R_REFLO - && *rello->sym_ptr_ptr == *reloc_entry->sym_ptr_ptr); - if (bfd_is_com_section (symbol->section)) relocation = 0; else @@ -1578,30 +1582,71 @@ ecoff_refhi_reloc (abfd, if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - vallo = bfd_get_32 (abfd, (bfd_byte *) data + rello->address) & 0xffff; - val = ((insn & 0xffff) << 16) + vallo; - val += relocation; - - /* The low order 16 bits are always treated as a signed value. - Therefore, a negative value in the low order bits requires an - adjustment in the high order bits. We need to make this - adjustment in two ways: once for the bits we took from the data, - and once for the bits we are putting back in to the data. */ - if ((vallo & 0x8000) != 0) - val -= 0x10000; - if ((val & 0x8000) != 0) - val += 0x10000; - - insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); - bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); + /* Save the information, and let REFLO do the actual relocation. */ + ecoff_refhi_addr = (bfd_byte *) data + reloc_entry->address; + ecoff_refhi_addend = relocation; - if (output_bfd != (bfd *) NULL) + if (output_bfd != (bfd *) NULL) reloc_entry->address += input_section->output_offset; return ret; } +/* Do a REFLO relocation. This is a straightforward 16 bit inplace + relocation; this function exists in order to do the REFHI + relocation described above. */ + +static bfd_reloc_status_type +ecoff_reflo_reloc (abfd, + reloc_entry, + symbol, + data, + input_section, + output_bfd) + bfd *abfd; + arelent *reloc_entry; + asymbol *symbol; + PTR data; + asection *input_section; + bfd *output_bfd; +{ + if (ecoff_refhi_addr != (bfd_byte *) NULL) + { + unsigned long insn; + unsigned long val; + unsigned long vallo; + + /* Do the REFHI relocation. Note that we actually don't need to + know anything about the REFLO itself, except where to find + the low 16 bits of the addend needed by the REFHI. */ + insn = bfd_get_32 (abfd, ecoff_refhi_addr); + vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address) + & 0xffff); + val = ((insn & 0xffff) << 16) + vallo; + val += ecoff_refhi_addend; + + /* The low order 16 bits are always treated as a signed value. + Therefore, a negative value in the low order bits requires an + adjustment in the high order bits. We need to make this + adjustment in two ways: once for the bits we took from the + data, and once for the bits we are putting back in to the + data. */ + if ((vallo & 0x8000) != 0) + val -= 0x10000; + if ((val & 0x8000) != 0) + val += 0x10000; + + insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff); + bfd_put_32 (abfd, insn, ecoff_refhi_addr); + + ecoff_refhi_addr = (bfd_byte *) NULL; + } + + /* Now do the REFLO reloc in the usual way. */ + return ecoff_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd); +} + /* Do a GPREL relocation. This is a 16 bit value which must become the offset from the gp register. */ @@ -1624,10 +1669,13 @@ ecoff_gprel_reloc (abfd, unsigned long val; unsigned long insn; - /* If we're relocating, and this an external symbol, we don't want - to change anything. */ + /* If we're relocating, and this is an external symbol with no + addend, we don't want to change anything. We will only have an + addend if this is a newly created reloc, not read from an ECOFF + file. */ if (output_bfd != (bfd *) NULL - && (symbol->flags & BSF_SECTION_SYM) == 0) + && (symbol->flags & BSF_SECTION_SYM) == 0 + && reloc_entry->addend == 0) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; @@ -1648,8 +1696,11 @@ ecoff_gprel_reloc (abfd, /* We have to figure out the gp value, so that we can adjust the symbol value correctly. We look up the symbol _gp in the output BFD. If we can't find it, we're stuck. We cache it in the ECOFF - target data. */ - if (ecoff_data (output_bfd)->gp == 0) + target data. We don't need to adjust the symbol value for an + external symbol if we are producing relocateable output. */ + if (ecoff_data (output_bfd)->gp == 0 + && (relocateable == false + || (symbol->flags & BSF_SECTION_SYM) != 0)) { if (relocateable != false) { @@ -1703,15 +1754,17 @@ ecoff_gprel_reloc (abfd, insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - /* Set val to the offset into the section (if we are relocating - against an external symbol, insn & 0xffff will be zero and so - will reloc_entry->addend). */ + /* Set val to the offset into the section or symbol. */ val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff; if (val & 0x8000) val -= 0x10000; - /* Adjust val for the final section location and GP value. */ - val += (relocation - ecoff_data (output_bfd)->gp); + /* Adjust val for the final section location and GP value. If we + are producing relocateable output, we don't want to do this for + an external symbol. */ + if (relocateable == false + || (symbol->flags & BSF_SECTION_SYM) != 0) + val += relocation - ecoff_data (output_bfd)->gp; insn = (insn &~ 0xffff) | (val & 0xffff); bfd_put_32 (abfd, insn, (bfd_byte *) data + reloc_entry->address); @@ -1822,7 +1875,7 @@ static reloc_howto_type ecoff_howto_table[] = 0, /* bitpos */ false, /* absolute (obsolete) */ true, /* complain_on_overflow */ - ecoff_generic_reloc, /* special_function */ + ecoff_reflo_reloc, /* special_function */ "REFLO", /* name */ true, /* partial_inplace */ 0xffff, /* src_mask */ @@ -2041,6 +2094,9 @@ ecoff_bfd_reloc_type_lookup (abfd, code) case BFD_RELOC_LO16: ecoff_type = ECOFF_R_REFLO; break; + case BFD_RELOC_MIPS_GPREL: + ecoff_type = ECOFF_R_GPREL; + break; default: return (CONST struct reloc_howto_struct *) NULL; } diff --git a/bfd/seclet.c b/bfd/seclet.c index 5b4d7648260..5dcc59ab0ef 100644 --- a/bfd/seclet.c +++ b/bfd/seclet.c @@ -79,10 +79,7 @@ DEFUN(rel,(abfd, seclet, output_section, data, relocateable), PTR data AND boolean relocateable) { - - if (output_section->flags & SEC_HAS_CONTENTS - && !(output_section->flags & SEC_NEVER_LOAD) - && (output_section->flags & SEC_LOAD) + if ((output_section->flags & SEC_HAS_CONTENTS) != 0 && seclet->size) { data = (PTR) bfd_get_relocated_section_contents(abfd, seclet, data, -- 2.30.2