X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/e48f985cd2daae5674391935a16ad687e21ecab6..2cd086e38750f157f0e38c174848929b2c7abf95:/bfd/aoutx.h diff --git a/bfd/aoutx.h b/bfd/aoutx.h index ca56a50c76..97d3f617b5 100644 --- a/bfd/aoutx.h +++ b/bfd/aoutx.h @@ -121,7 +121,6 @@ DESCRIPTION #define KEEPIT flags #define KEEPITTYPE int -#include #include /* For strchr and friends */ #include "bfd.h" #include @@ -134,6 +133,10 @@ DESCRIPTION #include "aout/ar.h" static boolean aout_get_external_symbols PARAMS ((bfd *)); +static boolean translate_from_native_sym_flags + PARAMS ((bfd *, aout_symbol_type *)); +static boolean translate_to_native_sym_flags + PARAMS ((bfd *, asymbol *, struct external_nlist *)); /* SUBSECTION @@ -198,6 +201,29 @@ HOWTO( 7, 0, 4, 64, true, 0, complain_overflow_signed, 0,"DISP64", tr { -1 }, HOWTO( 9, 0, 1, 16, false, 0, complain_overflow_bitfield,0,"BASE16", false,0xffffffff,0xffffffff, false), HOWTO(10, 0, 2, 32, false, 0, complain_overflow_bitfield,0,"BASE32", false,0xffffffff,0xffffffff, false), +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, + HOWTO(16, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"JMP_TABLE", false, 0,0x00000000, false), +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, + HOWTO(32, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"RELATIVE", false, 0,0x00000000, false), +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, +{ -1 }, + HOWTO(40, 0, 2, 0, false, 0, complain_overflow_bitfield,0,"BASEREL", false, 0,0x00000000, false), }; #define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0])) @@ -334,7 +360,23 @@ NAME(aout,swap_exec_header_out) (abfd, execp, raw_bytes) PUT_WORD (abfd, execp->a_drsize, bytes->e_drsize); } +/* Make all the section for an a.out file. */ +boolean +NAME(aout,make_sections) (abfd) + bfd *abfd; +{ + if (obj_textsec (abfd) == (asection *) NULL + && bfd_make_section (abfd, ".text") == (asection *) NULL) + return false; + if (obj_datasec (abfd) == (asection *) NULL + && bfd_make_section (abfd, ".data") == (asection *) NULL) + return false; + if (obj_bsssec (abfd) == (asection *) NULL + && bfd_make_section (abfd, ".bss") == (asection *) NULL) + return false; + return true; +} /* FUNCTION @@ -394,16 +436,28 @@ NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p) if (N_MAGIC (*execp) == ZMAGIC) { - abfd->flags |= D_PAGED|WP_TEXT; - adata(abfd).magic = z_magic; + abfd->flags |= D_PAGED | WP_TEXT; + adata (abfd).magic = z_magic; + } + else if (N_MAGIC (*execp) == QMAGIC) + { + abfd->flags |= D_PAGED | WP_TEXT; + adata (abfd).magic = z_magic; + adata (abfd).subformat = q_magic_format; } else if (N_MAGIC (*execp) == NMAGIC) { abfd->flags |= WP_TEXT; - adata(abfd).magic = n_magic; + adata (abfd).magic = n_magic; } + else if (N_MAGIC (*execp) == OMAGIC) + adata (abfd).magic = o_magic; else - adata(abfd).magic = o_magic; + { + /* Should have been checked with N_BADMAG before this routine + was called. */ + abort (); + } bfd_get_start_address (abfd) = execp->a_entry; @@ -420,18 +474,8 @@ NAME(aout,some_aout_object_p) (abfd, execp, callback_to_real_object_p) obj_aout_external_strings (abfd) = NULL; obj_aout_sym_hashes (abfd) = NULL; - /* Create the sections. This is raunchy, but bfd_close wants to reclaim - them. */ - - obj_textsec (abfd) = bfd_make_section_old_way (abfd, ".text"); - obj_datasec (abfd) = bfd_make_section_old_way (abfd, ".data"); - obj_bsssec (abfd) = bfd_make_section_old_way (abfd, ".bss"); - -#if 0 - (void)bfd_make_section (abfd, ".text"); - (void)bfd_make_section (abfd, ".data"); - (void)bfd_make_section (abfd, ".bss"); -#endif + if (! NAME(aout,make_sections) (abfd)) + return NULL; obj_datasec (abfd)->_raw_size = execp->a_data; obj_bsssec (abfd)->_raw_size = execp->a_bss; @@ -565,17 +609,9 @@ NAME(aout,mkobject) (abfd) abfd->tdata.aout_data = rawptr; exec_hdr (abfd) = &(rawptr->e); - /* For simplicity's sake we just make all the sections right here. */ - obj_textsec (abfd) = (asection *)NULL; obj_datasec (abfd) = (asection *)NULL; obj_bsssec (abfd) = (asection *)NULL; - bfd_make_section (abfd, ".text"); - bfd_make_section (abfd, ".data"); - bfd_make_section (abfd, ".bss"); - bfd_make_section (abfd, BFD_ABS_SECTION_NAME); - bfd_make_section (abfd, BFD_UND_SECTION_NAME); - bfd_make_section (abfd, BFD_COM_SECTION_NAME); return true; } @@ -601,13 +637,15 @@ DESCRIPTION */ enum machine_type -NAME(aout,machine_type) (arch, machine) +NAME(aout,machine_type) (arch, machine, unknown) enum bfd_architecture arch; unsigned long machine; + boolean *unknown; { enum machine_type arch_flags; arch_flags = M_UNKNOWN; + *unknown = true; switch (arch) { case bfd_arch_sparc: @@ -617,7 +655,7 @@ NAME(aout,machine_type) (arch, machine) case bfd_arch_m68k: switch (machine) { case 0: arch_flags = M_68010; break; - case 68000: arch_flags = M_UNKNOWN; break; + case 68000: arch_flags = M_UNKNOWN; *unknown = false; break; case 68010: arch_flags = M_68010; break; case 68020: arch_flags = M_68020; break; default: arch_flags = M_UNKNOWN; break; @@ -647,6 +685,10 @@ NAME(aout,machine_type) (arch, machine) default: arch_flags = M_UNKNOWN; } + + if (arch_flags != M_UNKNOWN) + *unknown = false; + return arch_flags; } @@ -676,9 +718,14 @@ NAME(aout,set_arch_mach) (abfd, arch, machine) if (! bfd_default_set_arch_mach (abfd, arch, machine)) return false; - if (arch != bfd_arch_unknown && - NAME(aout,machine_type) (arch, machine) == M_UNKNOWN) - return false; /* We can't represent this type */ + if (arch != bfd_arch_unknown) + { + boolean unknown; + + NAME(aout,machine_type) (arch, machine, &unknown); + if (unknown) + return false; + } /* Determine the size of a relocation entry */ switch (arch) { @@ -798,7 +845,10 @@ adjust_z_magic (abfd, execp) execp->a_text = obj_textsec(abfd)->_raw_size; if (ztih && (!abdp || (abdp && !abdp->exec_header_not_counted))) execp->a_text += adata(abfd).exec_bytes_size; - N_SET_MAGIC (*execp, ZMAGIC); + if (obj_aout_subformat (abfd) == q_magic_format) + N_SET_MAGIC (*execp, QMAGIC); + else + N_SET_MAGIC (*execp, ZMAGIC); /* Spec says data section should be rounded up to page boundary. */ obj_datasec(abfd)->_raw_size @@ -878,12 +928,11 @@ NAME(aout,adjust_sizes_and_vmas) (abfd, text_size, text_end) { struct internal_exec *execp = exec_hdr (abfd); - if ((obj_textsec (abfd) == NULL) || (obj_datasec (abfd) == NULL)) - { - bfd_set_error (bfd_error_invalid_operation); - return false; - } - if (adata(abfd).magic != undecided_magic) return true; + if (! NAME(aout,make_sections) (abfd)) + return false; + + if (adata(abfd).magic != undecided_magic) + return true; obj_textsec(abfd)->_raw_size = align_power(obj_textsec(abfd)->_raw_size, @@ -908,7 +957,6 @@ NAME(aout,adjust_sizes_and_vmas) (abfd, text_size, text_end) if (abfd->flags & D_PAGED) /* Whether or not WP_TEXT is set -- let D_PAGED override. */ - /* @@ What about QMAGIC? */ adata(abfd).magic = z_magic; else if (abfd->flags & WP_TEXT) adata(abfd).magic = n_magic; @@ -1045,44 +1093,6 @@ NAME(aout,set_section_contents) (abfd, section, location, offset, count) return true; } -/* Classify stabs symbols */ - -#define sym_in_text_section(sym) \ - (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_TEXT) - -#define sym_in_data_section(sym) \ - (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_DATA) - -#define sym_in_bss_section(sym) \ - (((sym)->type & (N_ABS | N_TEXT | N_DATA | N_BSS))== N_BSS) - -/* Symbol is undefined if type is N_UNDF|N_EXT and if it has - zero in the "value" field. Nonzeroes there are fortrancommon - symbols. */ -#define sym_is_undefined(sym) \ - ((sym)->type == (N_UNDF | N_EXT) && (sym)->symbol.value == 0) - -/* Symbol is a global definition if N_EXT is on and if it has - a nonzero type field. */ -#define sym_is_global_defn(sym) \ - (((sym)->type & N_EXT) && (sym)->type & N_TYPE) - -/* Symbol is debugger info if any bits outside N_TYPE or N_EXT - are on. */ -#define sym_is_debugger_info(sym) \ - (((sym)->type & ~(N_EXT | N_TYPE)) || (sym)->type == N_FN) - -#define sym_is_fortrancommon(sym) \ - (((sym)->type == (N_EXT)) && (sym)->symbol.value != 0) - -/* Symbol is absolute if it has N_ABS set */ -#define sym_is_absolute(sym) \ - (((sym)->type & N_TYPE)== N_ABS) - - -#define sym_is_indirect(sym) \ - (((sym)->type & N_ABS)== N_ABS) - /* Read the external symbols from an a.out file. */ static boolean @@ -1119,7 +1129,8 @@ aout_get_external_symbols (abfd) obj_aout_external_sym_count (abfd) = count; } - if (obj_aout_external_strings (abfd) == NULL) + if (obj_aout_external_strings (abfd) == NULL + && exec_hdr (abfd)->a_syms != 0) { unsigned char string_chars[BYTES_IN_WORD]; bfd_size_type stringsize; @@ -1159,302 +1170,353 @@ aout_get_external_symbols (abfd) return true; } -/* Only in their own functions for ease of debugging; when sym flags have - stabilised these should be inlined into their (single) caller */ +/* Translate an a.out symbol into a BFD symbol. The desc, other, type + and symbol->value fields of CACHE_PTR will be set from the a.out + nlist structure. This function is responsible for setting + symbol->flags and symbol->section, and adjusting symbol->value. */ static boolean -translate_from_native_sym_flags (sym_pointer, cache_ptr, abfd) - struct external_nlist *sym_pointer; - aout_symbol_type * cache_ptr; - bfd * abfd; +translate_from_native_sym_flags (abfd, cache_ptr) + bfd *abfd; + aout_symbol_type *cache_ptr; { - cache_ptr->symbol.section = 0; - switch (cache_ptr->type & N_TYPE) + flagword visible; + + if ((cache_ptr->type & N_STAB) != 0 + || cache_ptr->type == N_FN) + { + asection *sec; + + /* This is a debugging symbol. */ + + cache_ptr->symbol.flags = BSF_DEBUGGING; + + /* Work out the symbol section. */ + switch (cache_ptr->type & N_TYPE) + { + case N_TEXT: + case N_FN: + sec = obj_textsec (abfd); + break; + case N_DATA: + sec = obj_datasec (abfd); + break; + case N_BSS: + sec = obj_bsssec (abfd); + break; + default: + case N_ABS: + sec = &bfd_abs_section; + break; + } + + cache_ptr->symbol.section = sec; + cache_ptr->symbol.value -= sec->vma; + + return true; + } + + /* Get the default visibility. This does not apply to all types, so + we just hold it in a local variable to use if wanted. */ + if ((cache_ptr->type & N_EXT) == 0) + visible = BSF_LOCAL; + else + visible = BSF_GLOBAL; + + switch (cache_ptr->type) { + default: + case N_ABS: case N_ABS | N_EXT: + cache_ptr->symbol.section = &bfd_abs_section; + cache_ptr->symbol.flags = visible; + break; + + case N_UNDF | N_EXT: + if (cache_ptr->symbol.value != 0) + { + /* This is a common symbol. */ + cache_ptr->symbol.flags = BSF_GLOBAL; + cache_ptr->symbol.section = &bfd_com_section; + } + else + { + cache_ptr->symbol.flags = 0; + cache_ptr->symbol.section = &bfd_und_section; + } + break; + + case N_TEXT: case N_TEXT | N_EXT: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = visible; + break; + + /* N_SETV symbols used to represent set vectors placed in the + data section. They are no longer generated. Theoretically, + it was possible to extract the entries and combine them with + new ones, although I don't know if that was ever actually + done. Unless that feature is restored, treat them as data + symbols. */ + case N_SETV: case N_SETV | N_EXT: + case N_DATA: case N_DATA | N_EXT: + cache_ptr->symbol.section = obj_datasec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = visible; + break; + + case N_BSS: case N_BSS | N_EXT: + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = visible; + break; + case N_SETA: case N_SETA | N_EXT: case N_SETT: case N_SETT | N_EXT: case N_SETD: case N_SETD | N_EXT: case N_SETB: case N_SETB | N_EXT: { - char *copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1); asection *section; + arelent_chain *reloc; asection *into_section; - arelent_chain *reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); - if (!copy || !reloc) + /* This is a set symbol. The name of the symbol is the name + of the set (e.g., __CTOR_LIST__). The value of the symbol + is the value to add to the set. We create a section with + the same name as the symbol, and add a reloc to insert the + appropriate value into the section. + + This action is actually obsolete; it used to make the + linker do the right thing, but the linker no longer uses + this function. */ + + section = bfd_get_section_by_name (abfd, cache_ptr->symbol.name); + if (section == NULL) + { + char *copy; + + copy = bfd_alloc (abfd, strlen (cache_ptr->symbol.name) + 1); + if (copy == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + strcpy (copy, cache_ptr->symbol.name); + section = bfd_make_section (abfd, copy); + if (section == NULL) + return false; + } + + reloc = (arelent_chain *) bfd_alloc (abfd, sizeof (arelent_chain)); + if (reloc == NULL) { bfd_set_error (bfd_error_no_memory); return false; } - strcpy (copy, cache_ptr->symbol.name); - - /* Make sure that this bfd has a section with the right contructor - name */ - section = bfd_get_section_by_name (abfd, copy); - if (!section) - section = bfd_make_section (abfd, copy); - - /* Build a relocation entry for the constructor */ - switch ((cache_ptr->type & N_TYPE)) + /* Build a relocation entry for the constructor. */ + switch (cache_ptr->type & N_TYPE) { - case N_SETA: case N_SETA | N_EXT: + case N_SETA: into_section = &bfd_abs_section; cache_ptr->type = N_ABS; break; - case N_SETT: case N_SETT | N_EXT: - into_section = (asection *) obj_textsec (abfd); + case N_SETT: + into_section = obj_textsec (abfd); cache_ptr->type = N_TEXT; break; - case N_SETD: case N_SETD | N_EXT: - into_section = (asection *) obj_datasec (abfd); + case N_SETD: + into_section = obj_datasec (abfd); cache_ptr->type = N_DATA; break; - case N_SETB: case N_SETB | N_EXT: - into_section = (asection *) obj_bsssec (abfd); + case N_SETB: + into_section = obj_bsssec (abfd); cache_ptr->type = N_BSS; break; - default: - bfd_set_error (bfd_error_bad_value); - return false; } - /* Build a relocation pointing into the constuctor section - pointing at the symbol in the set vector specified */ - + /* Build a relocation pointing into the constructor section + pointing at the symbol in the set vector specified. */ reloc->relent.addend = cache_ptr->symbol.value; - cache_ptr->symbol.section = into_section->symbol->section; + cache_ptr->symbol.section = into_section; reloc->relent.sym_ptr_ptr = into_section->symbol_ptr_ptr; - - /* We modify the symbol to belong to a section depending upon the - name of the symbol - probably __CTOR__ or __DTOR__ but we don't - really care, and add to the size of the section to contain a - pointer to the symbol. Build a reloc entry to relocate to this - symbol attached to this section. */ - + /* We modify the symbol to belong to a section depending upon + the name of the symbol, and add to the size of the section + to contain a pointer to the symbol. Build a reloc entry to + relocate to this symbol attached to this section. */ section->flags = SEC_CONSTRUCTOR | SEC_RELOC; - section->reloc_count++; section->alignment_power = 2; reloc->next = section->constructor_chain; section->constructor_chain = reloc; reloc->relent.address = section->_raw_size; - section->_raw_size += sizeof (int *); + section->_raw_size += BYTES_IN_WORD; + + if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE) + reloc->relent.howto = howto_table_ext + CTOR_TABLE_RELOC_IDX; + else + reloc->relent.howto = howto_table_std + CTOR_TABLE_RELOC_IDX; - reloc->relent.howto - = (obj_reloc_entry_size(abfd) == RELOC_EXT_SIZE - ? howto_table_ext : howto_table_std) - + CTOR_TABLE_RELOC_IDX; cache_ptr->symbol.flags |= BSF_CONSTRUCTOR; } break; - default: - if (cache_ptr->type == N_WARNING) - { - /* This symbol is the text of a warning message, the next symbol - is the symbol to associate the warning with */ - cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING; - - /* @@ Stuffing pointers into integers is a no-no. - We can usually get away with it if the integer is - large enough though. */ - if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) - abort (); - cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1)); - - /* We don't use a warning symbol's section, but we need - it to be nonzero for the sanity check below, so - pick one arbitrarily. */ - cache_ptr->symbol.section = &bfd_abs_section; - - /* We furgle with the next symbol in place. - We don't want it to be undefined, we'll trample the type */ - (sym_pointer + 1)->e_type[0] = 0xff; - break; - } - if ((cache_ptr->type | N_EXT) == (N_INDR | N_EXT)) - { - /* Two symbols in a row for an INDR message. The first symbol - contains the name we will match, the second symbol contains - the name the first name is translated into. It is supplied to - us undefined. This is good, since we want to pull in any files - which define it */ - cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT; - - /* @@ Stuffing pointers into integers is a no-no. - We can usually get away with it if the integer is - large enough though. */ - if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) - abort (); - - cache_ptr->symbol.value = (bfd_vma) ((cache_ptr + 1)); - cache_ptr->symbol.section = &bfd_ind_section; - } - else if (sym_is_debugger_info (cache_ptr)) - { - cache_ptr->symbol.flags = BSF_DEBUGGING; - /* Work out the section correct for this symbol */ - switch (cache_ptr->type & N_TYPE) - { - case N_TEXT: - case N_FN: - cache_ptr->symbol.section = obj_textsec (abfd); - cache_ptr->symbol.value -= obj_textsec (abfd)->vma; - break; - case N_DATA: - cache_ptr->symbol.value -= obj_datasec (abfd)->vma; - cache_ptr->symbol.section = obj_datasec (abfd); - break; - case N_BSS: - cache_ptr->symbol.section = obj_bsssec (abfd); - cache_ptr->symbol.value -= obj_bsssec (abfd)->vma; - break; - default: - case N_ABS: - cache_ptr->symbol.section = &bfd_abs_section; - break; - } - } - else - { + case N_WARNING: + /* This symbol is the text of a warning message. The next + symbol is the symbol to associate the warning with. If a + reference is made to that symbol, a warning is issued. */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_WARNING; - if (sym_is_fortrancommon (cache_ptr)) - { - cache_ptr->symbol.flags = 0; - cache_ptr->symbol.section = &bfd_com_section; - } - else - { + /* @@ Stuffing pointers into integers is a no-no. We can + usually get away with it if the integer is large enough + though. */ + if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) + abort (); + cache_ptr->symbol.value = (bfd_vma) (cache_ptr + 1); + cache_ptr->symbol.section = &bfd_abs_section; - } + break; - /* In a.out, the value of a symbol is always relative to the - * start of the file, if this is a data symbol we'll subtract - * the size of the text section to get the section relative - * value. If this is a bss symbol (which would be strange) - * we'll subtract the size of the previous two sections - * to find the section relative address. - */ + case N_INDR: case N_INDR | N_EXT: + /* An indirect symbol. This consists of two symbols in a row. + The first symbol is the name of the indirection. The second + symbol is the name of the target. A reference to the first + symbol becomes a reference to the second. */ + cache_ptr->symbol.flags = BSF_DEBUGGING | BSF_INDIRECT | visible; - if (sym_in_text_section (cache_ptr)) - { - cache_ptr->symbol.value -= obj_textsec (abfd)->vma; - cache_ptr->symbol.section = obj_textsec (abfd); - } - else if (sym_in_data_section (cache_ptr)) - { - cache_ptr->symbol.value -= obj_datasec (abfd)->vma; - cache_ptr->symbol.section = obj_datasec (abfd); - } - else if (sym_in_bss_section (cache_ptr)) - { - cache_ptr->symbol.section = obj_bsssec (abfd); - cache_ptr->symbol.value -= obj_bsssec (abfd)->vma; - } - else if (sym_is_undefined (cache_ptr)) - { - cache_ptr->symbol.flags = 0; - cache_ptr->symbol.section = &bfd_und_section; - } - else if (sym_is_absolute (cache_ptr)) - { - cache_ptr->symbol.section = &bfd_abs_section; - } + /* @@ Stuffing pointers into integers is a no-no. We can + usually get away with it if the integer is large enough + though. */ + if (sizeof (cache_ptr + 1) > sizeof (bfd_vma)) + abort (); + cache_ptr->symbol.value = (bfd_vma) (cache_ptr + 1); - if (sym_is_global_defn (cache_ptr)) - { - cache_ptr->symbol.flags = BSF_GLOBAL | BSF_EXPORT; - } - else if (! sym_is_undefined (cache_ptr)) - { - cache_ptr->symbol.flags = BSF_LOCAL; - } - } + cache_ptr->symbol.section = &bfd_ind_section; + + break; + + case N_WEAKU: + cache_ptr->symbol.section = &bfd_und_section; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKA: + cache_ptr->symbol.section = &bfd_abs_section; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKT: + cache_ptr->symbol.section = obj_textsec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKD: + cache_ptr->symbol.section = obj_datasec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = BSF_WEAK; + break; + + case N_WEAKB: + cache_ptr->symbol.section = obj_bsssec (abfd); + cache_ptr->symbol.value -= cache_ptr->symbol.section->vma; + cache_ptr->symbol.flags = BSF_WEAK; + break; } - if (cache_ptr->symbol.section == 0) - abort (); + return true; } +/* Set the fields of SYM_POINTER according to CACHE_PTR. */ static boolean -translate_to_native_sym_flags (sym_pointer, cache_ptr, abfd) - struct external_nlist *sym_pointer; - asymbol *cache_ptr; +translate_to_native_sym_flags (abfd, cache_ptr, sym_pointer) bfd *abfd; + asymbol *cache_ptr; + struct external_nlist *sym_pointer; { bfd_vma value = cache_ptr->value; - /* mask out any existing type bits in case copying from one section - to another */ + /* Mask out any existing type bits in case copying from one section + to another. */ sym_pointer->e_type[0] &= ~N_TYPE; - /* We attempt to order these tests by decreasing frequency of success, - according to tcov when linking the linker. */ - if (bfd_get_output_section(cache_ptr) == &bfd_abs_section) { + if (bfd_get_section (cache_ptr) == &bfd_abs_section) sym_pointer->e_type[0] |= N_ABS; - } - else if (bfd_get_output_section(cache_ptr) == obj_textsec (abfd)) { + else if (bfd_get_section (cache_ptr) == obj_textsec (abfd) + || (bfd_get_section (cache_ptr)->output_section + == obj_textsec (abfd))) sym_pointer->e_type[0] |= N_TEXT; - } - else if (bfd_get_output_section(cache_ptr) == obj_datasec (abfd)) { + else if (bfd_get_section (cache_ptr) == obj_datasec (abfd) + || (bfd_get_section (cache_ptr)->output_section + == obj_datasec (abfd))) sym_pointer->e_type[0] |= N_DATA; - } - else if (bfd_get_output_section(cache_ptr) == obj_bsssec (abfd)) { + else if (bfd_get_section (cache_ptr) == obj_bsssec (abfd) + || (bfd_get_section (cache_ptr)->output_section + == obj_bsssec (abfd))) sym_pointer->e_type[0] |= N_BSS; - } - else if (bfd_get_output_section(cache_ptr) == &bfd_und_section) { - sym_pointer->e_type[0] = (N_UNDF | N_EXT); - } - else if (bfd_get_output_section(cache_ptr) == &bfd_ind_section) { + else if (bfd_get_section (cache_ptr) == &bfd_und_section) + sym_pointer->e_type[0] = N_UNDF | N_EXT; + else if (bfd_get_section (cache_ptr) == &bfd_ind_section) sym_pointer->e_type[0] = N_INDR; - } - else if (bfd_get_output_section(cache_ptr) == NULL) { - /* Protect the bfd_is_com_section call. - This case occurs, e.g., for the *DEBUG* section of a COFF file. */ - bfd_set_error (bfd_error_nonrepresentable_section); - return false; - } - else if (bfd_is_com_section (bfd_get_output_section (cache_ptr))) { - sym_pointer->e_type[0] = (N_UNDF | N_EXT); - } - else { - bfd_set_error (bfd_error_nonrepresentable_section); - return false; - } + else if (bfd_get_section (cache_ptr) == NULL) + { + /* Protect the bfd_is_com_section call. This case occurs, e.g., + for the *DEBUG* section of a COFF file. */ + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + else if (bfd_is_com_section (bfd_get_section (cache_ptr))) + sym_pointer->e_type[0] = N_UNDF | N_EXT; + else + { + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } /* Turn the symbol from section relative to absolute again */ + value += cache_ptr->section->vma; - value += cache_ptr->section->output_section->vma + cache_ptr->section->output_offset ; - - - if (cache_ptr->flags & (BSF_WARNING)) { + if ((cache_ptr->flags & BSF_WARNING) != 0) sym_pointer->e_type[0] = N_WARNING; - (sym_pointer+1)->e_type[0] = 1; - } - if (cache_ptr->flags & BSF_DEBUGGING) { - sym_pointer->e_type[0] = ((aout_symbol_type *)cache_ptr)->type; - } - else if (cache_ptr->flags & (BSF_GLOBAL | BSF_EXPORT)) { + if ((cache_ptr->flags & BSF_DEBUGGING) != 0) + sym_pointer->e_type[0] = ((aout_symbol_type *) cache_ptr)->type; + else if ((cache_ptr->flags & BSF_GLOBAL) != 0) sym_pointer->e_type[0] |= N_EXT; - } - if (cache_ptr->flags & BSF_CONSTRUCTOR) { - int type = ((aout_symbol_type *)cache_ptr)->type; - switch (type) - { - case N_ABS: type = N_SETA; break; - case N_TEXT: type = N_SETT; break; - case N_DATA: type = N_SETD; break; - case N_BSS: type = N_SETB; break; - } - sym_pointer->e_type[0] = type; - } + + if ((cache_ptr->flags & BSF_CONSTRUCTOR) != 0) + { + int type = ((aout_symbol_type *) cache_ptr)->type; + switch (type) + { + case N_ABS: type = N_SETA; break; + case N_TEXT: type = N_SETT; break; + case N_DATA: type = N_SETD; break; + case N_BSS: type = N_SETB; break; + } + sym_pointer->e_type[0] = type; + } + + if ((cache_ptr->flags & BSF_WEAK) != 0) + { + int type; + + switch (sym_pointer->e_type[0] & N_TYPE) + { + default: + case N_ABS: type = N_WEAKA; break; + case N_TEXT: type = N_WEAKT; break; + case N_DATA: type = N_WEAKD; break; + case N_BSS: type = N_WEAKB; break; + case N_UNDF: type = N_WEAKU; break; + } + sym_pointer->e_type[0] = type; + } PUT_WORD(abfd, value, sym_pointer->e_value); @@ -1463,7 +1525,6 @@ translate_to_native_sym_flags (sym_pointer, cache_ptr, abfd) /* Native-level interface to symbols. */ - asymbol * NAME(aout,make_empty_symbol) (abfd) bfd *abfd; @@ -1520,7 +1581,7 @@ NAME(aout,translate_symbol_table) (abfd, in, ext, count, str, strsize, dynamic) in->type = bfd_h_get_8 (abfd, ext->e_type); in->symbol.udata = 0; - if (!translate_from_native_sym_flags (ext, in, abfd)) + if (! translate_from_native_sym_flags (abfd, in)) return false; if (dynamic) @@ -1560,13 +1621,12 @@ NAME(aout,slurp_symbol_table) (abfd) cached_size = (obj_aout_external_sym_count (abfd) * sizeof (aout_symbol_type)); cached = (aout_symbol_type *) malloc (cached_size); - memset (cached, 0, cached_size); - if (cached == NULL) { bfd_set_error (bfd_error_no_memory); return false; } + memset (cached, 0, cached_size); /* Convert from external symbol information to internal. */ if (! (NAME(aout,translate_symbol_table) @@ -1599,424 +1659,226 @@ NAME(aout,slurp_symbol_table) (abfd) return true; } -/* Possible improvements: +/* We use a hash table when writing out symbols so that we only write + out a particular string once. This helps particularly when the + linker writes out stabs debugging entries, because each different + contributing object file tends to have many duplicate stabs + strings. + + Possible improvements: + look for strings matching trailing substrings of other strings + better data structures? balanced trees? - + smaller per-string or per-symbol data? re-use some of the symbol's - data fields? - + also look at reducing memory use elsewhere -- maybe if we didn't have to - construct the entire symbol table at once, we could get by with smaller - amounts of VM? (What effect does that have on the string table - reductions?) - + rip this out of here, put it into its own file in bfd or libiberty, so - coff and elf can use it too. I'll work on this soon, but have more - pressing tasks right now. - - A hash table might(?) be more efficient for handling exactly the cases that - are handled now, but for trailing substring matches, I think we want to - examine the `nearest' values (reverse-)lexically, not merely impose a strict - order, nor look only for exact-match or not-match. I don't think a hash - table would be very useful for that, and I don't feel like fleshing out two - completely different implementations. [raeburn:930419.0331EDT] */ - -struct stringtab_entry { - /* Hash value for this string. Only useful so long as we aren't doing - substring matches. */ - unsigned int hash; - - /* Next node to look at, depending on whether the hash value of the string - being searched for is less than or greater than the hash value of the - current node. For now, `equal to' is lumped in with `greater than', for - space efficiency. It's not a common enough case to warrant another field - to be used for all nodes. */ - struct stringtab_entry *less; - struct stringtab_entry *greater; - - /* The string itself. */ - CONST char *string; - - /* The index allocated for this string. */ - bfd_size_type index; - -#ifdef GATHER_STATISTICS - /* How many references have there been to this string? (Not currently used; - could be dumped out for anaylsis, if anyone's interested.) */ - unsigned long count; -#endif - - /* Next node in linked list, in suggested output order. */ - struct stringtab_entry *next_to_output; -}; + + look at reducing memory use elsewhere -- maybe if we didn't have + to construct the entire symbol table at once, we could get by + with smaller amounts of VM? (What effect does that have on the + string table reductions?) -struct stringtab_data { - /* Tree of string table entries. */ - struct stringtab_entry *strings; + This hash table code breaks dbx on SunOS 4.1.3, so we don't do it + if BFD_TRADITIONAL_FORMAT is set. */ - /* Fudge factor used to center top node of tree. */ - int hash_zero; +/* An entry in the strtab hash table. */ - /* Next index value to issue. */ +struct strtab_hash_entry +{ + struct bfd_hash_entry root; + /* Index in string table. */ bfd_size_type index; - - /* Index used for empty strings. Cached here because checking for them - is really easy, and we can avoid searching the tree. */ - bfd_size_type empty_string_index; - - /* These fields indicate the two ends of a singly-linked list that indicates - the order strings should be written out in. Use this order, and no - seeking will need to be done, so output efficiency should be maximized. */ - struct stringtab_entry **end; - struct stringtab_entry *output_order; - -#ifdef GATHER_STATISTICS - /* Number of strings which duplicate strings already in the table. */ - unsigned long duplicates; - - /* Number of bytes saved by not having to write all the duplicate strings. */ - unsigned long bytes_saved; - - /* Number of zero-length strings. Currently, these all turn into - references to the null byte at the end of the first string. In some - cases (possibly not all? explore this...), it should be possible to - simply write out a zero index value. */ - unsigned long empty_strings; - - /* Number of times the hash values matched but the strings were different. - Note that this includes the number of times the other string(s) occurs, so - there may only be two strings hashing to the same value, even if this - number is very large. */ - unsigned long bad_hash_matches; - - /* Null strings aren't counted in this one. - This will probably only be nonzero if we've got an input file - which was produced by `ld -r' (i.e., it's already been processed - through this code). Under some operating systems, native tools - may make all empty strings have the same index; but the pointer - check won't catch those, because to get to that stage we'd already - have to compute the checksum, which requires reading the string, - so we short-circuit that case with empty_string_index above. */ - unsigned long pointer_matches; - - /* Number of comparisons done. I figure with the algorithms in use below, - the average number of comparisons done (per symbol) should be roughly - log-base-2 of the number of unique strings. */ - unsigned long n_compares; -#endif + /* Next string in strtab. */ + struct strtab_hash_entry *next; }; -/* Some utility functions for the string table code. */ +/* The strtab hash table. */ -/* For speed, only hash on the first this many bytes of strings. - This number was chosen by profiling ld linking itself, with -g. */ -#define HASHMAXLEN 25 +struct strtab_hash +{ + struct bfd_hash_table table; + /* Size of strtab--also next available index. */ + bfd_size_type size; + /* First string in strtab. */ + struct strtab_hash_entry *first; + /* Last string in strtab. */ + struct strtab_hash_entry *last; +}; -#define HASH_CHAR(c) (sum ^= sum >> 20, sum ^= sum << 7, sum += (c)) +static struct bfd_hash_entry *strtab_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +static boolean stringtab_init PARAMS ((struct strtab_hash *)); +static bfd_size_type add_to_stringtab + PARAMS ((bfd *, struct strtab_hash *, const char *, boolean)); +static boolean emit_stringtab PARAMS ((bfd *, struct strtab_hash *)); -static INLINE unsigned int -hash (string, len) - unsigned char *string; - register unsigned int len; +/* Routine to create an entry in a strtab. */ + +static struct bfd_hash_entry * +strtab_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; { - register unsigned int sum = 0; + struct strtab_hash_entry *ret = (struct strtab_hash_entry *) entry; - if (len > HASHMAXLEN) + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct strtab_hash_entry *) NULL) + ret = ((struct strtab_hash_entry *) + bfd_hash_allocate (table, sizeof (struct strtab_hash_entry))); + if (ret == (struct strtab_hash_entry *) NULL) { - HASH_CHAR (len); - len = HASHMAXLEN; + bfd_set_error (bfd_error_no_memory); + return NULL; } - while (len--) + /* Call the allocation method of the superclass. */ + ret = ((struct strtab_hash_entry *) + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); + + if (ret) { - HASH_CHAR (*string++); + /* Initialize the local fields. */ + ret->index = (bfd_size_type) -1; + ret->next = NULL; } - return sum; -} -static INLINE void -stringtab_init (tab) - struct stringtab_data *tab; -{ - tab->strings = 0; - tab->output_order = 0; - tab->hash_zero = 0; - tab->end = &tab->output_order; - - /* Initial string table length includes size of length field. */ - tab->index = BYTES_IN_WORD; - tab->empty_string_index = -1; -#ifdef GATHER_STATISTICS - tab->duplicates = 0; - tab->empty_strings = 0; - tab->bad_hash_matches = 0; - tab->pointer_matches = 0; - tab->bytes_saved = 0; - tab->n_compares = 0; -#endif + return (struct bfd_hash_entry *) ret; } -static INLINE int -compare (entry, str, hash) - struct stringtab_entry *entry; - CONST char *str; - unsigned int hash; -{ - return hash - entry->hash; -} +/* Look up an entry in an strtab. */ + +#define strtab_hash_lookup(t, string, create, copy) \ + ((struct strtab_hash_entry *) \ + bfd_hash_lookup (&(t)->table, (string), (create), (copy))) + +/* Create a new strtab. */ -#ifdef GATHER_STATISTICS -/* Don't want to have to link in math library with all bfd applications... */ -static INLINE double -log2 (num) - int num; +static boolean +stringtab_init (table) + struct strtab_hash *table; { - double d = num; - int n = 0; - while (d >= 2.0) - n++, d /= 2.0; - return ((d > 1.41) ? 0.5 : 0) + n; + if (! bfd_hash_table_init (&table->table, strtab_hash_newfunc)) + return false; + + /* Leave space for the size of the string table. */ + table->size = BYTES_IN_WORD; + + table->first = NULL; + table->last = NULL; + + return true; } -#endif -/* Main string table routines. */ -/* Returns index in string table. Whether or not this actually adds an - entry into the string table should be irrelevant -- it just has to - return a valid index. */ -static bfd_size_type -add_to_stringtab (abfd, str, tab) +/* Free a strtab. */ + +#define stringtab_free(tab) bfd_hash_table_free (&(tab)->table) + +/* Get the index of a string in a strtab, adding it if it is not + already present. If HASH is false, we don't really use the hash + table, and we don't eliminate duplicate strings. */ + +static INLINE bfd_size_type +add_to_stringtab (abfd, tab, str, copy) bfd *abfd; - CONST char *str; - struct stringtab_data *tab; + struct strtab_hash *tab; + const char *str; + boolean copy; { - struct stringtab_entry **ep; - register struct stringtab_entry *entry; - unsigned int hashval, len; + register struct strtab_hash_entry *entry; - if (str[0] == 0) - { - bfd_size_type index; - CONST bfd_size_type minus_one = -1; - -#ifdef GATHER_STATISTICS - tab->empty_strings++; -#endif - index = tab->empty_string_index; - if (index != minus_one) - { - got_empty: -#ifdef GATHER_STATISTICS - tab->bytes_saved++; - tab->duplicates++; -#endif - return index; - } + /* An index of 0 always means the empty string. */ + if (*str == '\0') + return 0; - /* Need to find it. */ - entry = tab->strings; - if (entry) - { - index = entry->index + strlen (entry->string); - tab->empty_string_index = index; - goto got_empty; - } - len = 0; - } - else - len = strlen (str); - - /* The hash_zero value is chosen such that the first symbol gets a value of - zero. With a balanced tree, this wouldn't be very useful, but without it, - we might get a more even split at the top level, instead of skewing it - badly should hash("/usr/lib/crt0.o") (or whatever) be far from zero. */ - hashval = hash (str, len) ^ tab->hash_zero; - ep = &tab->strings; - if (!*ep) + if ((abfd->flags & BFD_TRADITIONAL_FORMAT) == 0) { - tab->hash_zero = hashval; - hashval = 0; - goto add_it; + entry = strtab_hash_lookup (tab, str, true, copy); + if (entry == NULL) + return (bfd_size_type) -1; } - - while (*ep) + else { - register int cmp; - - entry = *ep; -#ifdef GATHER_STATISTICS - tab->n_compares++; -#endif - cmp = compare (entry, str, hashval); - /* The not-equal cases are more frequent, so check them first. */ - if (cmp > 0) - ep = &entry->greater; - else if (cmp < 0) - ep = &entry->less; + entry = ((struct strtab_hash_entry *) + bfd_hash_allocate (&tab->table, + sizeof (struct strtab_hash_entry))); + if (entry == NULL) + return (bfd_size_type) -1; + if (! copy) + entry->root.string = str; else { - if (entry->string == str) - { -#ifdef GATHER_STATISTICS - tab->pointer_matches++; -#endif - goto match; - } - /* Compare the first bytes to save a function call if they - don't match. */ - if (entry->string[0] == str[0] && !strcmp (entry->string, str)) - { - match: -#ifdef GATHER_STATISTICS - entry->count++; - tab->bytes_saved += len + 1; - tab->duplicates++; -#endif - /* If we're in the linker, and the new string is from a new - input file which might have already had these reductions - run over it, we want to keep the new string pointer. I - don't think we're likely to see any (or nearly as many, - at least) cases where a later string is in the same location - as an earlier one rather than this one. */ - entry->string = str; - return entry->index; - } -#ifdef GATHER_STATISTICS - tab->bad_hash_matches++; -#endif - ep = &entry->greater; + char *n; + + n = (char *) bfd_hash_allocate (&tab->table, strlen (str) + 1); + if (n == NULL) + return (bfd_size_type) -1; + entry->root.string = n; } + entry->index = (bfd_size_type) -1; + entry->next = NULL; } - /* If we get here, nothing that's in the table already matched. - EP points to the `next' field at the end of the chain; stick a - new entry on here. */ - add_it: - entry = (struct stringtab_entry *) - bfd_alloc_by_size_t (abfd, sizeof (struct stringtab_entry)); - if (!entry) + if (entry->index == (bfd_size_type) -1) { - bfd_set_error (bfd_error_no_memory); - abort(); /* FIXME */ + entry->index = tab->size; + tab->size += strlen (str) + 1; + if (tab->first == NULL) + tab->first = entry; + else + tab->last->next = entry; + tab->last = entry; } - entry->less = entry->greater = 0; - entry->hash = hashval; - entry->index = tab->index; - entry->string = str; - entry->next_to_output = 0; -#ifdef GATHER_STATISTICS - entry->count = 1; -#endif - - assert (*tab->end == 0); - *(tab->end) = entry; - tab->end = &entry->next_to_output; - assert (*tab->end == 0); - - { - tab->index += len + 1; - if (len == 0) - tab->empty_string_index = entry->index; - } - assert (*ep == 0); - *ep = entry; return entry->index; } +/* Write out a strtab. ABFD is already at the right location in the + file. */ + static boolean -emit_strtab (abfd, tab) - bfd *abfd; - struct stringtab_data *tab; +emit_stringtab (abfd, tab) + register bfd *abfd; + struct strtab_hash *tab; { - struct stringtab_entry *entry; -#ifdef GATHER_STATISTICS - int count = 0; -#endif - - /* Be sure to put string length into correct byte ordering before writing - it out. */ - char buffer[BYTES_IN_WORD]; + bfd_byte buffer[BYTES_IN_WORD]; + register struct strtab_hash_entry *entry; - PUT_WORD (abfd, tab->index, (unsigned char *) buffer); + PUT_WORD (abfd, tab->size, buffer); if (bfd_write ((PTR) buffer, 1, BYTES_IN_WORD, abfd) != BYTES_IN_WORD) return false; - for (entry = tab->output_order; entry; entry = entry->next_to_output) + for (entry = tab->first; entry != NULL; entry = entry->next) { - size_t len = strlen (entry->string) + 1; + register const char *str; + register size_t len; - if (bfd_write ((PTR) entry->string, 1, len, abfd) != len) + str = entry->root.string; + len = strlen (str) + 1; + if (bfd_write ((PTR) str, 1, len, abfd) != len) return false; - -#ifdef GATHER_STATISTICS - count++; -#endif } -#ifdef GATHER_STATISTICS - /* Short form only, for now. - To do: Specify output file. Conditionalize on environment? Detailed - analysis if desired. */ - { - int n_syms = bfd_get_symcount (abfd); - - fprintf (stderr, "String table data for output file:\n"); - fprintf (stderr, " %8d symbols output\n", n_syms); - fprintf (stderr, " %8d duplicate strings\n", tab->duplicates); - fprintf (stderr, " %8d empty strings\n", tab->empty_strings); - fprintf (stderr, " %8d unique strings output\n", count); - fprintf (stderr, " %8d pointer matches\n", tab->pointer_matches); - fprintf (stderr, " %8d bytes saved\n", tab->bytes_saved); - fprintf (stderr, " %8d bad hash matches\n", tab->bad_hash_matches); - fprintf (stderr, " %8d hash-val comparisons\n", tab->n_compares); - if (n_syms) - { - double n_compares = tab->n_compares; - double avg_compares = n_compares / n_syms; - /* The second value here should usually be near one. */ - fprintf (stderr, - "\t average %f comparisons per symbol (%f * log2 nstrings)\n", - avg_compares, avg_compares / log2 (count)); - } - } -#endif - -/* Old code: - unsigned int count; - generic = bfd_get_outsymbols(abfd); - for (count = 0; count < bfd_get_symcount(abfd); count++) - { - asymbol *g = *(generic++); - - if (g->name) - { - size_t length = strlen(g->name)+1; - bfd_write((PTR)g->name, 1, length, abfd); - } - g->KEEPIT = (KEEPITTYPE) count; - } */ - return true; } - + boolean NAME(aout,write_syms) (abfd) bfd *abfd; { unsigned int count ; asymbol **generic = bfd_get_outsymbols (abfd); - struct stringtab_data strtab; + struct strtab_hash strtab; - stringtab_init (&strtab); + if (! stringtab_init (&strtab)) + return false; for (count = 0; count < bfd_get_symcount (abfd); count++) { asymbol *g = generic[count]; + bfd_size_type indx; struct external_nlist nsp; - if (g->name) - PUT_WORD (abfd, add_to_stringtab (abfd, g->name, &strtab), - (unsigned char *) nsp.e_strx); - else - PUT_WORD (abfd, 0, (unsigned char *)nsp.e_strx); + indx = add_to_stringtab (abfd, &strtab, g->name, false); + if (indx == (bfd_size_type) -1) + goto error_return; + PUT_WORD (abfd, indx, (bfd_byte *) nsp.e_strx); if (bfd_asymbol_flavour(g) == abfd->xvec->flavour) { @@ -2031,19 +1893,28 @@ NAME(aout,write_syms) (abfd) bfd_h_put_8(abfd, 0, nsp.e_type); } - if (! translate_to_native_sym_flags (&nsp, g, abfd)) - return false; + if (! translate_to_native_sym_flags (abfd, g, &nsp)) + goto error_return; if (bfd_write((PTR)&nsp,1,EXTERNAL_NLIST_SIZE, abfd) != EXTERNAL_NLIST_SIZE) - return false; + goto error_return; /* NB: `KEEPIT' currently overlays `flags', so set this only here, at the end. */ g->KEEPIT = count; } - return emit_strtab (abfd, &strtab); + if (! emit_stringtab (abfd, &strtab)) + goto error_return; + + stringtab_free (&strtab); + + return true; + +error_return: + stringtab_free (&strtab); + return false; } @@ -2088,9 +1959,8 @@ NAME(aout,swap_std_reloc_out) (abfd, g, natptr) r_pcrel = (int) g->howto->pc_relative; /* Relative to PC? */ /* XXX This relies on relocs coming from a.out files. */ r_baserel = (g->howto->type & 8) != 0; - /* r_jmptable, r_relative??? FIXME-soon */ - r_jmptable = 0; - r_relative = 0; + r_jmptable = (g->howto->type & 16) != 0; + r_relative = (g->howto->type & 32) != 0; #if 0 /* For a standard reloc, the addend is in the object file. */ @@ -2353,13 +2223,11 @@ NAME(aout,swap_std_reloc_in) (abfd, bytes, cache_ptr, symbols) >> RELOC_STD_BITS_LENGTH_SH_LITTLE; } - howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel; + howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel + + 16 * r_jmptable + 32 * r_relative; BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std)); cache_ptr->howto = howto_table_std + howto_idx; BFD_ASSERT (cache_ptr->howto->type != -1); - BFD_ASSERT (r_jmptable == 0); - BFD_ASSERT (r_relative == 0); - /* FIXME-soon: Roll jmptable, relative bits into howto setting */ MOVE_ADDRESS(0); } @@ -2513,6 +2381,12 @@ NAME(aout,canonicalize_reloc) (abfd, section, relptr, symbols) arelent *tblptr = section->relocation; unsigned int count; + if (section == obj_bsssec (abfd)) + { + *relptr = NULL; + return 0; + } + if (!(tblptr || NAME(aout,slurp_reloc_table)(abfd, section, symbols))) return -1; @@ -2559,6 +2433,9 @@ NAME(aout,get_reloc_upper_bound) (abfd, asect) * ((exec_hdr(abfd)->a_trsize / obj_reloc_entry_size (abfd)) + 1)); + if (asect == obj_bsssec (abfd)) + return sizeof (arelent *); + bfd_set_error (bfd_error_invalid_operation); return -1; } @@ -2804,26 +2681,6 @@ NAME(aout,bfd_free_cached_info) (abfd) /* a.out link code. */ -/* a.out linker hash table entries. */ - -struct aout_link_hash_entry -{ - struct bfd_link_hash_entry root; - /* Symbol index in output file. */ - int indx; -}; - -/* a.out linker hash table. */ - -struct aout_link_hash_table -{ - struct bfd_link_hash_table root; -}; - -static struct bfd_hash_entry *aout_link_hash_newfunc - PARAMS ((struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string)); static boolean aout_link_add_object_symbols PARAMS ((bfd *, struct bfd_link_info *)); static boolean aout_link_check_archive_element @@ -2836,8 +2693,8 @@ static boolean aout_link_add_symbols /* Routine to create an entry in an a.out link hash table. */ -static struct bfd_hash_entry * -aout_link_hash_newfunc (entry, table, string) +struct bfd_hash_entry * +NAME(aout,link_hash_newfunc) (entry, table, string) struct bfd_hash_entry *entry; struct bfd_hash_table *table; const char *string; @@ -2860,12 +2717,28 @@ aout_link_hash_newfunc (entry, table, string) _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); if (ret) - /* Set local fields. */ - ret->indx = -1; + { + /* Set local fields. */ + ret->written = false; + ret->indx = -1; + } return (struct bfd_hash_entry *) ret; } +/* Initialize an a.out link hash table. */ + +boolean +NAME(aout,link_hash_table_init) (table, abfd, newfunc) + struct aout_link_hash_table *table; + bfd *abfd; + struct bfd_hash_entry *(*newfunc) PARAMS ((struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *)); +{ + return _bfd_link_hash_table_init (&table->root, abfd, newfunc); +} + /* Create an a.out link hash table. */ struct bfd_link_hash_table * @@ -2881,8 +2754,8 @@ NAME(aout,link_hash_table_create) (abfd) bfd_set_error (bfd_error_no_memory); return (struct bfd_link_hash_table *) NULL; } - if (! _bfd_link_hash_table_init (&ret->root, abfd, - aout_link_hash_newfunc)) + if (! NAME(aout,link_hash_table_init) (ret, abfd, + NAME(aout,link_hash_newfunc))) { free (ret); return (struct bfd_link_hash_table *) NULL; @@ -2890,25 +2763,6 @@ NAME(aout,link_hash_table_create) (abfd) return &ret->root; } -/* Look up an entry in an a.out link hash table. */ - -#define aout_link_hash_lookup(table, string, create, copy, follow) \ - ((struct aout_link_hash_entry *) \ - bfd_link_hash_lookup (&(table)->root, (string), (create), (copy), (follow))) - -/* Traverse an a.out link hash table. */ - -#define aout_link_hash_traverse(table, func, info) \ - (bfd_link_hash_traverse \ - (&(table)->root, \ - (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ - (info))) - -/* Get the a.out link hash table from the info structure. This is - just a cast. */ - -#define aout_hash_table(p) ((struct aout_link_hash_table *) ((p)->hash)) - /* Given an a.out BFD, add symbols to the global hash table as appropriate. */ @@ -3033,8 +2887,14 @@ aout_link_check_ar_symbols (abfd, info, pneeded) const char *name; struct bfd_link_hash_entry *h; - /* Ignore symbols that are not externally visible. */ - if ((type & N_EXT) == 0) + /* Ignore symbols that are not externally visible. This is an + optimization only, as we check the type more thoroughly + below. */ + if ((type & N_EXT) == 0 + && type != N_WEAKA + && type != N_WEAKT + && type != N_WEAKD + && type != N_WEAKB) { if (type == N_WARNING || type == N_INDR) @@ -3070,7 +2930,13 @@ aout_link_check_ar_symbols (abfd, info, pneeded) int a; and this object file from the archive includes int a = 5; - In such a case we must include this object file. */ + In such a case we must include this object file. + + FIXME: The SunOS 4.1.3 linker will pull in the archive + element if the symbol is defined in the .data section, + but not if it is defined in the .text section. That + seems a bit crazy to me, and I haven't implemented it. + However, it might be correct. */ if (! (*info->callbacks->add_archive_element) (info, abfd, name)) return false; *pneeded = true; @@ -3120,6 +2986,23 @@ aout_link_check_ar_symbols (abfd, info, pneeded) } } } + + if (type == N_WEAKA + || type == N_WEAKT + || type == N_WEAKD + || type == N_WEAKB) + { + /* This symbol is weak but defined. We must pull it in if + the current link symbol is undefined, but we don't want + it if the current link symbol is common. */ + if (h->type == bfd_link_hash_undefined) + { + if (! (*info->callbacks->add_archive_element) (info, abfd, name)) + return false; + *pneeded = true; + return true; + } + } } /* We do not need this object file. */ @@ -3133,6 +3016,11 @@ aout_link_add_symbols (abfd, info) bfd *abfd; struct bfd_link_info *info; { + boolean (*add_one_symbol) PARAMS ((struct bfd_link_info *, bfd *, + const char *, flagword, asection *, + bfd_vma, const char *, boolean, + boolean, + struct bfd_link_hash_entry **)); bfd_size_type sym_count; char *strings; boolean copy; @@ -3155,13 +3043,24 @@ aout_link_add_symbols (abfd, info) bfd_alloc (abfd, ((size_t) sym_count * sizeof (struct aout_link_hash_entry *)))); - if (!sym_hash) + if (sym_hash == NULL && sym_count != 0) { bfd_set_error (bfd_error_no_memory); return false; } obj_aout_sym_hashes (abfd) = sym_hash; + if ((abfd->flags & DYNAMIC) != 0 + && aout_backend_info (abfd)->add_dynamic_symbols != NULL) + { + if (! (*aout_backend_info (abfd)->add_dynamic_symbols) (abfd, info)) + return false; + } + + add_one_symbol = aout_backend_info (abfd)->add_one_symbol; + if (add_one_symbol == NULL) + add_one_symbol = _bfd_generic_link_add_one_symbol; + p = obj_aout_external_syms (abfd); pend = p + sym_count; for (; p < pend; p++, sym_hash++) @@ -3181,29 +3080,6 @@ aout_link_add_symbols (abfd, info) if ((type & N_STAB) != 0) continue; - /* Ignore symbols that are not external. */ - if ((type & N_EXT) == 0 - && type != N_WARNING - && type != N_SETA - && type != N_SETT - && type != N_SETD - && type != N_SETB) - { - /* If this is an N_INDR symbol we must skip the next entry, - which is the symbol to indirect to (actually, an N_INDR - symbol without N_EXT set is pretty useless). */ - if (type == N_INDR) - { - ++p; - ++sym_hash; - } - continue; - } - - /* Ignore N_FN symbols (these appear to have N_EXT set). */ - if (type == N_FN) - continue; - name = strings + GET_WORD (abfd, p->e_strx); value = GET_WORD (abfd, p->e_value); flags = BSF_GLOBAL; @@ -3212,11 +3088,32 @@ aout_link_add_symbols (abfd, info) { default: abort (); + + case N_UNDF: + case N_ABS: + case N_TEXT: + case N_DATA: + case N_BSS: + case N_FN_SEQ: + case N_COMM: + case N_SETV: + case N_FN: + /* Ignore symbols that are not externally visible. */ + continue; + case N_INDR: + /* Ignore local indirect symbol. */ + ++p; + ++sym_hash; + continue; + case N_UNDF | N_EXT: - if (value != 0) - section = &bfd_com_section; + if (value == 0) + { + section = &bfd_und_section; + flags = 0; + } else - section = &bfd_und_section; + section = &bfd_com_section; break; case N_ABS | N_EXT: section = &bfd_abs_section; @@ -3226,6 +3123,9 @@ aout_link_add_symbols (abfd, info) value -= bfd_get_section_vma (abfd, section); break; case N_DATA | N_EXT: + case N_SETV | N_EXT: + /* Treat N_SETV symbols as N_DATA symbol; see comment in + translate_from_native_sym_flags. */ section = obj_datasec (abfd); value -= bfd_get_section_vma (abfd, section); break; @@ -3274,9 +3174,32 @@ aout_link_add_symbols (abfd, info) section = &bfd_und_section; flags |= BSF_WARNING; break; + case N_WEAKU: + section = &bfd_und_section; + flags = BSF_WEAK; + break; + case N_WEAKA: + section = &bfd_abs_section; + flags = BSF_WEAK; + break; + case N_WEAKT: + section = obj_textsec (abfd); + value -= bfd_get_section_vma (abfd, section); + flags = BSF_WEAK; + break; + case N_WEAKD: + section = obj_datasec (abfd); + value -= bfd_get_section_vma (abfd, section); + flags = BSF_WEAK; + break; + case N_WEAKB: + section = obj_bsssec (abfd); + value -= bfd_get_section_vma (abfd, section); + flags = BSF_WEAK; + break; } - if (! (_bfd_generic_link_add_one_symbol + if (! ((*add_one_symbol) (info, abfd, name, flags, section, value, string, copy, false, (struct bfd_link_hash_entry **) sym_hash))) return false; @@ -3302,7 +3225,7 @@ struct aout_final_link_info /* File position of symbols. */ file_ptr symoff; /* String table. */ - struct stringtab_data strtab; + struct strtab_hash strtab; }; static boolean aout_link_input_bfd @@ -3381,13 +3304,15 @@ NAME(aout,final_link) (abfd, info, callback) abort (); } } - trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd) - ->link_order_head) - * obj_reloc_entry_size (abfd)); + if (obj_textsec (abfd) != (asection *) NULL) + trsize += (_bfd_count_link_order_relocs (obj_textsec (abfd) + ->link_order_head) + * obj_reloc_entry_size (abfd)); exec_hdr (abfd)->a_trsize = trsize; - drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd) - ->link_order_head) - * obj_reloc_entry_size (abfd)); + if (obj_datasec (abfd) != (asection *) NULL) + drsize += (_bfd_count_link_order_relocs (obj_datasec (abfd) + ->link_order_head) + * obj_reloc_entry_size (abfd)); exec_hdr (abfd)->a_drsize = drsize; } @@ -3417,7 +3342,8 @@ NAME(aout,final_link) (abfd, info, callback) obj_aout_external_sym_count (abfd) = 0; /* We accumulate the string table as we write out the symbols. */ - stringtab_init (&aout_info.strtab); + if (! stringtab_init (&aout_info.strtab)) + return false; /* The most time efficient way to do the link would be to read all the input object files into memory and then sort out the @@ -3505,6 +3431,13 @@ NAME(aout,final_link) (abfd, info, callback) } } + /* Finish up any dynamic linking we may be doing. */ + if (aout_backend_info (abfd)->finish_dynamic_link != NULL) + { + if (! (*aout_backend_info (abfd)->finish_dynamic_link) (abfd, info)) + return false; + } + /* Update the header information. */ abfd->symcount = obj_aout_external_sym_count (abfd); exec_hdr (abfd)->a_syms = abfd->symcount * EXTERNAL_NLIST_SIZE; @@ -3517,7 +3450,7 @@ NAME(aout,final_link) (abfd, info, callback) /* Write out the string table. */ if (bfd_seek (abfd, obj_str_filepos (abfd), SEEK_SET) != 0) return false; - return emit_strtab (abfd, &aout_info.strtab); + return emit_stringtab (abfd, &aout_info.strtab); } /* Link an a.out input BFD into the output file. */ @@ -3532,6 +3465,14 @@ aout_link_input_bfd (finfo, input_bfd) BFD_ASSERT (bfd_get_format (input_bfd) == bfd_object); + /* If this is a dynamic object, it may need special handling. */ + if ((input_bfd->flags & DYNAMIC) != 0 + && aout_backend_info (input_bfd)->link_dynamic_object != NULL) + { + return ((*aout_backend_info (input_bfd)->link_dynamic_object) + (finfo->info, input_bfd)); + } + /* Get the symbols. We probably have them already, unless finfo->info->keep_memory is false. */ if (! aout_get_external_symbols (input_bfd)) @@ -3596,6 +3537,7 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) enum bfd_link_discard discard; struct external_nlist *output_syms = NULL; struct external_nlist *outsym; + bfd_size_type strtab_index; register struct external_nlist *sym; struct external_nlist *sym_end; struct aout_link_hash_entry **sym_hash; @@ -3627,10 +3569,11 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) bfd_h_put_8 (output_bfd, N_TEXT, outsym->e_type); bfd_h_put_8 (output_bfd, 0, outsym->e_other); bfd_h_put_16 (output_bfd, (bfd_vma) 0, outsym->e_desc); - PUT_WORD (output_bfd, - add_to_stringtab (output_bfd, input_bfd->filename, - &finfo->strtab), - outsym->e_strx); + strtab_index = add_to_stringtab (output_bfd, &finfo->strtab, + input_bfd->filename, false); + if (strtab_index == (bfd_size_type) -1) + goto error_return; + PUT_WORD (output_bfd, strtab_index, outsym->e_strx); PUT_WORD (output_bfd, (bfd_get_section_vma (output_bfd, obj_textsec (input_bfd)->output_section) @@ -3653,6 +3596,7 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) boolean skip; asection *symsec; bfd_vma val = 0; + boolean copy; *symbol_map = -1; @@ -3696,7 +3640,8 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) || h->root.type == bfd_link_hash_warning)) { hresolve = (struct aout_link_hash_entry *) h->root.u.i.link; - while (hresolve->root.type == bfd_link_hash_indirect) + while (hresolve->root.type == bfd_link_hash_indirect + || hresolve->root.type == bfd_link_hash_warning) hresolve = ((struct aout_link_hash_entry *) hresolve->root.u.i.link); *sym_hash = hresolve; @@ -3704,8 +3649,11 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) /* If the symbol has already been written out, skip it. */ if (h != (struct aout_link_hash_entry *) NULL - && h->root.written) + && h->root.type != bfd_link_hash_warning + && h->written) { + if ((type & N_TYPE) == N_INDR) + skip_indirect = true; *symbol_map = h->indx; continue; } @@ -3732,18 +3680,22 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) if (skip) { if (h != (struct aout_link_hash_entry *) NULL) - h->root.written = true; + h->written = true; continue; } /* Get the value of the symbol. */ - if ((type & N_TYPE) == N_TEXT) + if ((type & N_TYPE) == N_TEXT + || type == N_WEAKT) symsec = obj_textsec (input_bfd); - else if ((type & N_TYPE) == N_DATA) + else if ((type & N_TYPE) == N_DATA + || type == N_WEAKD) symsec = obj_datasec (input_bfd); - else if ((type & N_TYPE) == N_BSS) + else if ((type & N_TYPE) == N_BSS + || type == N_WEAKB) symsec = obj_bsssec (input_bfd); - else if ((type & N_TYPE) == N_ABS) + else if ((type & N_TYPE) == N_ABS + || type == N_WEAKA) symsec = &bfd_abs_section; else if (((type & N_TYPE) == N_INDR && (hresolve == (struct aout_link_hash_entry *) NULL @@ -3816,6 +3768,11 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) } else if (hresolve->root.type == bfd_link_hash_common) val = hresolve->root.u.c.size; + else if (hresolve->root.type == bfd_link_hash_weak) + { + val = 0; + type = N_WEAKU; + } else val = 0; @@ -3831,7 +3788,7 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) it is a local symbol see if we should discard it. */ if (h != (struct aout_link_hash_entry *) NULL) { - h->root.written = true; + h->written = true; h->indx = obj_aout_external_sym_count (output_bfd); } else @@ -3866,6 +3823,7 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) outsym->e_other); bfd_h_put_16 (output_bfd, bfd_h_get_16 (input_bfd, sym->e_desc), outsym->e_desc); + copy = false; if (! finfo->info->keep_memory) { /* name points into a string table which we are going to @@ -3874,17 +3832,13 @@ aout_link_write_symbols (finfo, input_bfd, symbol_map) if (h != (struct aout_link_hash_entry *) NULL) name = (*sym_hash)->root.root.string; else - { - char *n; - - n = bfd_alloc (output_bfd, strlen (name) + 1); - strcpy (n, name); - name = n; - } + copy = true; } - PUT_WORD (output_bfd, - add_to_stringtab (output_bfd, name, &finfo->strtab), - outsym->e_strx); + strtab_index = add_to_stringtab (output_bfd, &finfo->strtab, + name, copy); + if (strtab_index == (bfd_size_type) -1) + goto error_return; + PUT_WORD (output_bfd, strtab_index, outsym->e_strx); PUT_WORD (output_bfd, val, outsym->e_value); *symbol_map = obj_aout_external_sym_count (output_bfd); ++obj_aout_external_sym_count (output_bfd); @@ -3928,11 +3882,24 @@ aout_link_write_other_symbol (h, data) int type; bfd_vma val; struct external_nlist outsym; + bfd_size_type indx; + + output_bfd = finfo->output_bfd; + + if (aout_backend_info (output_bfd)->write_dynamic_symbol != NULL) + { + if (! ((*aout_backend_info (output_bfd)->write_dynamic_symbol) + (output_bfd, finfo->info, h))) + { + /* FIXME: No way to handle errors. */ + abort (); + } + } - if (h->root.written) + if (h->written) return true; - h->root.written = true; + h->written = true; if (finfo->info->strip == strip_all || (finfo->info->strip == strip_some @@ -3940,8 +3907,6 @@ aout_link_write_other_symbol (h, data) false, false) == NULL)) return true; - output_bfd = finfo->output_bfd; - switch (h->root.type) { default: @@ -3957,7 +3922,7 @@ aout_link_write_other_symbol (h, data) { asection *sec; - sec = h->root.u.def.section; + sec = h->root.u.def.section->output_section; BFD_ASSERT (sec == &bfd_abs_section || sec->owner == output_bfd); if (sec == obj_textsec (output_bfd)) @@ -3969,14 +3934,17 @@ aout_link_write_other_symbol (h, data) else type = N_ABS | N_EXT; val = (h->root.u.def.value - + sec->output_section->vma - + sec->output_offset); + + sec->vma + + h->root.u.def.section->output_offset); } break; case bfd_link_hash_common: type = N_UNDF | N_EXT; val = h->root.u.c.size; break; + case bfd_link_hash_weak: + type = N_WEAKU; + val = 0; case bfd_link_hash_indirect: case bfd_link_hash_warning: /* FIXME: Ignore these for now. The circumstances under which @@ -3987,9 +3955,14 @@ aout_link_write_other_symbol (h, data) bfd_h_put_8 (output_bfd, type, outsym.e_type); bfd_h_put_8 (output_bfd, 0, outsym.e_other); bfd_h_put_16 (output_bfd, 0, outsym.e_desc); - PUT_WORD (output_bfd, - add_to_stringtab (output_bfd, h->root.root.string, &finfo->strtab), - outsym.e_strx); + indx = add_to_stringtab (output_bfd, &finfo->strtab, h->root.root.string, + false); + if (indx == (bfd_size_type) -1) + { + /* FIXME: No way to handle errors. */ + abort (); + } + PUT_WORD (output_bfd, indx, outsym.e_strx); PUT_WORD (output_bfd, val, outsym.e_value); if (bfd_seek (output_bfd, finfo->symoff, SEEK_SET) != 0 @@ -4021,7 +3994,8 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr, { bfd_size_type input_size; bfd_byte *contents = NULL; - PTR relocs = NULL; + PTR relocs; + PTR free_relocs = NULL; /* Get the section contents. */ input_size = bfd_section_size (input_bfd, input_section); @@ -4035,16 +4009,22 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr, (file_ptr) 0, input_size)) goto error_return; - /* Read in the relocs. */ - relocs = (PTR) malloc (rel_size); - if (relocs == NULL && rel_size != 0) + /* Read in the relocs if we haven't already done it. */ + if (aout_section_data (input_section) != NULL + && aout_section_data (input_section)->relocs != NULL) + relocs = aout_section_data (input_section)->relocs; + else { - bfd_set_error (bfd_error_no_memory); - goto error_return; + relocs = free_relocs = (PTR) malloc (rel_size); + if (relocs == NULL && rel_size != 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 + || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size) + goto error_return; } - if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0 - || bfd_read (relocs, 1, rel_size, input_bfd) != rel_size) - goto error_return; /* Relocate the section contents. */ if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) @@ -4090,14 +4070,14 @@ aout_link_input_section (finfo, input_bfd, input_section, reloff_ptr, <= obj_datasec (finfo->output_bfd)->rel_filepos))); } - if (relocs != NULL) - free (relocs); + if (free_relocs != NULL) + free (free_relocs); if (contents != NULL) free (contents); return true; error_return: - if (relocs != NULL) - free (relocs); + if (free_relocs != NULL) + free (free_relocs); if (contents != NULL) free (contents); return false; @@ -4139,6 +4119,10 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs, bfd_byte *contents; int *symbol_map; { + boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *, + bfd *, asection *, + struct aout_link_hash_entry *, + PTR, boolean *)); bfd *output_bfd; boolean relocateable; struct external_nlist *syms; @@ -4149,6 +4133,7 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs, struct reloc_std_external *rel_end; output_bfd = finfo->output_bfd; + check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc; BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE); BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p @@ -4205,10 +4190,9 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs, >> RELOC_STD_BITS_LENGTH_SH_LITTLE); } - howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel; + howto_idx = r_length + 4 * r_pcrel + 8 * r_baserel + + 16 * r_jmptable + 32 * r_relative; BFD_ASSERT (howto_idx < TABLE_SIZE (howto_table_std)); - BFD_ASSERT (r_jmptable == 0); - BFD_ASSERT (r_relative == 0); if (relocateable) { @@ -4327,6 +4311,19 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs, struct aout_link_hash_entry *h; h = sym_hashes[r_index]; + + if (check_dynamic_reloc != NULL) + { + boolean skip; + + if (! ((*check_dynamic_reloc) + (finfo->info, input_bfd, input_section, h, + (PTR) rel, &skip))) + return false; + if (skip) + continue; + } + if (h != (struct aout_link_hash_entry *) NULL && h->root.type == bfd_link_hash_defined) { @@ -4334,6 +4331,9 @@ aout_link_input_section_std (finfo, input_bfd, input_section, relocs, + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); } + else if (h != (struct aout_link_hash_entry *) NULL + && h->root.type == bfd_link_hash_weak) + relocation = 0; else { const char *name; @@ -4411,6 +4411,10 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs, bfd_byte *contents; int *symbol_map; { + boolean (*check_dynamic_reloc) PARAMS ((struct bfd_link_info *, + bfd *, asection *, + struct aout_link_hash_entry *, + PTR, boolean *)); bfd *output_bfd; boolean relocateable; struct external_nlist *syms; @@ -4421,6 +4425,7 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs, struct reloc_ext_external *rel_end; output_bfd = finfo->output_bfd; + check_dynamic_reloc = aout_backend_info (output_bfd)->check_dynamic_reloc; BFD_ASSERT (obj_reloc_entry_size (input_bfd) == RELOC_EXT_SIZE); BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p @@ -4603,6 +4608,19 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs, struct aout_link_hash_entry *h; h = sym_hashes[r_index]; + + if (check_dynamic_reloc != NULL) + { + boolean skip; + + if (! ((*check_dynamic_reloc) + (finfo->info, input_bfd, input_section, h, + (PTR) rel, &skip))) + return false; + if (skip) + continue; + } + if (h != (struct aout_link_hash_entry *) NULL && h->root.type == bfd_link_hash_defined) { @@ -4610,6 +4628,9 @@ aout_link_input_section_ext (finfo, input_bfd, input_section, relocs, + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); } + else if (h != (struct aout_link_hash_entry *) NULL + && h->root.type == bfd_link_hash_weak) + relocation = 0; else { const char *name; @@ -4775,8 +4796,8 @@ aout_link_reloc_link_order (finfo, o, p) r_pcrel = howto->pc_relative; r_baserel = (howto->type & 8) != 0; - r_jmptable = 0; - r_relative = 0; + r_jmptable = (howto->type & 16) != 0; + r_relative = (howto->type & 32) != 0; r_length = howto->size; PUT_WORD (finfo->output_bfd, p->offset, srel.r_address); @@ -4822,7 +4843,7 @@ aout_link_reloc_link_order (finfo, o, p) boolean ok; size = bfd_get_reloc_size (howto); - buf = (bfd_byte*) bfd_zmalloc (size); + buf = (bfd_byte *) bfd_zmalloc (size); if (buf == (bfd_byte *) NULL) { bfd_set_error (bfd_error_no_memory);