diff options
-rw-r--r-- | bfd/ChangeLog | 36 | ||||
-rw-r--r-- | bfd/elf-bfd.h | 89 | ||||
-rw-r--r-- | bfd/elf-eh-frame.c | 177 | ||||
-rw-r--r-- | bfd/elf.c | 18 | ||||
-rw-r--r-- | bfd/elflink.h | 61 | ||||
-rw-r--r-- | bfd/po/SRC-POTFILES.in | 7 |
6 files changed, 199 insertions, 189 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9cf4abb..de54a92 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,41 @@ 2002-11-12 Alan Modra <amodra@bigpond.net.au> + * elf-bfd.h (struct cie_header): Move from elf_eh-frame.c. + (struct cie, struct eh_cie_fde, struct eh_frame_sec_info): Likewise. + (struct eh_frame_array_ent, struct eh_frame_hdr_info): Likewise. + (enum elf_link_info_type): Remove ELF_INFO_TYPE_EH_FRAME_HDR. + (struct eh_frame_hdr_info): Add "hdr_sec", remove "split". + (struct elf_link_hash_table): Add eh_info. + (struct elf_obj_tdata): Change eh_frame_hdr to an asection *. + (_bfd_elf_discard_section_eh_frame): Update prototype. + (_bfd_elf_discard_section_eh_frame_hdr): Likewise. + (_bfd_elf_write_section_eh_frame): Likewise. + (_bfd_elf_write_section_eh_frame_hdr): Likewise. + * elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Remove "ehdrsec" + param. Get "hdr_info" from link hash table. + (_bfd_elf_discard_section_eh_frame_hdr): Remove "sec" param. Get + header section from link hash table. Save header section to elf_tdata. + (_bfd_elf_maybe_strip_eh_frame_hdr): Remove local "sec". Use + header section from link hash table. Don't alloc hdr_info. Clear + hdr_sec instead of setting "strip". + (_bfd_elf_eh_frame_section_offset): Formatting. + (_bfd_elf_write_section_eh_frame): Remove "ehdrsec", add "info" param. + Get header section from link hash table. + (_bfd_elf_write_section_eh_frame_hdr): Remove "sec", add "info" param. + Get header section from link hash table. + * elf.c (map_sections_to_segments): Use cached eh_frame_hdr. + (get_program_header_size): Likewise. + (_bfd_elf_section_offset): Formatting. + * elflink.h (elf_link_create_dynamic_sections): Stash eh frame header + section pointer in link hash table. + (elf_bfd_final_link): Adjust _bfd_elf_write_section_eh_frame_hdr + and _bfd_elf_write_section_eh_frame calls. Update comment about + eh_frame entries. + (elf_bfd_discard_info): Adjust _bfd_elf_discard_section_eh_frame and + _bfd_elf_discard_section_eh_frame_hdr calls. Remove "ehdr". + + * po/SRC-POTFILES.in: Regenerate. + * elf-eh-frame.c (_bfd_elf_discard_section_eh_frame): Don't zero relocs for discarded FDEs. Remove dead code. (_bfd_elf_write_section_eh_frame_hdr): Remove dead code. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 78e39d9..2fae2b4 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -235,11 +235,79 @@ enum elf_link_info_type ELF_INFO_TYPE_STABS, ELF_INFO_TYPE_MERGE, ELF_INFO_TYPE_EH_FRAME, - ELF_INFO_TYPE_EH_FRAME_HDR, ELF_INFO_TYPE_JUST_SYMS, ELF_INFO_TYPE_LAST }; +/* Structures used by the eh_frame optimization code. */ +struct cie_header +{ + unsigned int length; + unsigned int id; +}; + +struct cie +{ + struct cie_header hdr; + unsigned char version; + unsigned char augmentation[20]; + unsigned int code_align; + int data_align; + unsigned int ra_column; + unsigned int augmentation_size; + struct elf_link_hash_entry *personality; + unsigned char per_encoding; + unsigned char lsda_encoding; + unsigned char fde_encoding; + unsigned char initial_insn_length; + unsigned char make_relative; + unsigned char make_lsda_relative; + unsigned char initial_instructions[50]; +}; + +struct eh_cie_fde +{ + unsigned int offset; + unsigned int size; + asection *sec; + unsigned int new_offset; + unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char lsda_offset; + unsigned char cie : 1; + unsigned char removed : 1; + unsigned char make_relative : 1; + unsigned char make_lsda_relative : 1; + unsigned char per_encoding_relative : 1; +}; + +struct eh_frame_sec_info +{ + unsigned int count; + unsigned int alloced; + struct eh_cie_fde entry[1]; +}; + +struct eh_frame_array_ent +{ + bfd_vma initial_loc; + bfd_vma fde; +}; + +struct eh_frame_hdr_info +{ + struct cie last_cie; + asection *last_cie_sec; + asection *hdr_sec; + unsigned int last_cie_offset; + unsigned int fde_count, array_count; + struct eh_frame_array_ent *array; + /* TRUE if .eh_frame_hdr should contain the sorted search table. + We build it if we successfully read all .eh_frame input sections + and recognize them. */ + boolean table; +}; + /* Cached start, size and alignment of PT_TLS segment. */ struct elf_link_tls_segment { @@ -294,6 +362,9 @@ struct elf_link_hash_table /* A pointer to information used to merge SEC_MERGE sections. */ PTR merge_info; + /* Used by eh_frame code when editing .eh_frame. */ + struct eh_frame_hdr_info eh_info; + /* A linked list of local symbols to be added to .dynsym. */ struct elf_link_local_dynamic_entry *dynlocal; @@ -1118,12 +1189,12 @@ struct elf_obj_tdata include this field for a MIPS ELF target. */ asection **local_stubs; - /* Used to determine if the e_flags field has been initialized */ - boolean flags_init; - /* Used to determine if PT_GNU_EH_FRAME segment header should be created. */ - boolean eh_frame_hdr; + asection *eh_frame_hdr; + + /* Used to determine if the e_flags field has been initialized */ + boolean flags_init; /* Number of symbol version definitions we are about to emit. */ unsigned int cverdefs; @@ -1366,16 +1437,16 @@ extern void _bfd_elf_strtab_finalize PARAMS ((struct elf_strtab_hash *)); extern boolean _bfd_elf_discard_section_eh_frame - PARAMS ((bfd *, struct bfd_link_info *, asection *, asection *, + PARAMS ((bfd *, struct bfd_link_info *, asection *, boolean (*) (bfd_vma, PTR), struct elf_reloc_cookie *)); extern boolean _bfd_elf_discard_section_eh_frame_hdr - PARAMS ((bfd *, struct bfd_link_info *, asection *)); + PARAMS ((bfd *, struct bfd_link_info *)); extern bfd_vma _bfd_elf_eh_frame_section_offset PARAMS ((bfd *, asection *, bfd_vma)); extern boolean _bfd_elf_write_section_eh_frame - PARAMS ((bfd *, asection *, asection *, bfd_byte *)); + PARAMS ((bfd *, struct bfd_link_info *, asection *, bfd_byte *)); extern boolean _bfd_elf_write_section_eh_frame_hdr - PARAMS ((bfd *, asection *)); + PARAMS ((bfd *, struct bfd_link_info *)); extern boolean _bfd_elf_maybe_strip_eh_frame_hdr PARAMS ((struct bfd_link_info *)); diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c index d5f4cc5..fa152ab 100644 --- a/bfd/elf-eh-frame.c +++ b/bfd/elf-eh-frame.c @@ -26,74 +26,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define EH_FRAME_HDR_SIZE 8 -struct cie_header -{ - unsigned int length; - unsigned int id; -}; - -struct cie -{ - struct cie_header hdr; - unsigned char version; - unsigned char augmentation[20]; - unsigned int code_align; - int data_align; - unsigned int ra_column; - unsigned int augmentation_size; - struct elf_link_hash_entry *personality; - unsigned char per_encoding; - unsigned char lsda_encoding; - unsigned char fde_encoding; - unsigned char initial_insn_length; - unsigned char make_relative; - unsigned char make_lsda_relative; - unsigned char initial_instructions[50]; -}; - -struct eh_cie_fde -{ - unsigned int offset; - unsigned int size; - asection *sec; - unsigned int new_offset; - unsigned char fde_encoding; - unsigned char lsda_encoding; - unsigned char lsda_offset; - unsigned char cie : 1; - unsigned char removed : 1; - unsigned char make_relative : 1; - unsigned char make_lsda_relative : 1; - unsigned char per_encoding_relative : 1; -}; - -struct eh_frame_sec_info -{ - unsigned int count; - unsigned int alloced; - struct eh_cie_fde entry[1]; -}; - -struct eh_frame_array_ent -{ - bfd_vma initial_loc; - bfd_vma fde; -}; - -struct eh_frame_hdr_info -{ - struct cie last_cie; - asection *last_cie_sec; - unsigned int last_cie_offset; - unsigned int fde_count, array_count; - struct eh_frame_array_ent *array; - /* TRUE if .eh_frame_hdr should contain the sorted search table. - We build it if we successfully read all .eh_frame input sections - and recognize them. */ - boolean table; - boolean strip; -}; - static bfd_vma read_unsigned_leb128 PARAMS ((bfd *, char *, unsigned int *)); static bfd_signed_vma read_signed_leb128 @@ -282,11 +214,11 @@ int cie_compare (c1, c2) deleted. */ boolean -_bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec, +_bfd_elf_discard_section_eh_frame (abfd, info, sec, reloc_symbol_deleted_p, cookie) bfd *abfd; struct bfd_link_info *info; - asection *sec, *ehdrsec; + asection *sec; boolean (*reloc_symbol_deleted_p) PARAMS ((bfd_vma, PTR)); struct elf_reloc_cookie *cookie; { @@ -294,6 +226,7 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec, bfd_byte *last_cie, *last_fde; struct cie_header hdr; struct cie cie; + struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int leb128_tmp; @@ -316,10 +249,8 @@ _bfd_elf_discard_section_eh_frame (abfd, info, sec, ehdrsec, return false; } - BFD_ASSERT (elf_section_data (ehdrsec)->sec_info_type - == ELF_INFO_TYPE_EH_FRAME_HDR); - hdr_info = (struct eh_frame_hdr_info *) - elf_section_data (ehdrsec)->sec_info; + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; /* Read the frame unwind information from abfd. */ @@ -740,32 +671,27 @@ free_no_table: input sections. It finalizes the size of .eh_frame_hdr section. */ boolean -_bfd_elf_discard_section_eh_frame_hdr (abfd, info, sec) +_bfd_elf_discard_section_eh_frame_hdr (abfd, info) bfd *abfd; struct bfd_link_info *info; - asection *sec; { + struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; + asection *sec; - if ((elf_section_data (sec)->sec_info_type - != ELF_INFO_TYPE_EH_FRAME_HDR) - || ! info->eh_frame_hdr) - { - _bfd_strip_section_from_output (info, sec); - return false; - } - - hdr_info = (struct eh_frame_hdr_info *) - elf_section_data (sec)->sec_info; - if (hdr_info->strip) + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + sec = hdr_info->hdr_sec; + if (sec == NULL) return false; + sec->_cooked_size = EH_FRAME_HDR_SIZE; if (hdr_info->table) sec->_cooked_size += 4 + hdr_info->fde_count * 8; /* Request program headers to be recalculated. */ elf_tdata (abfd)->program_header_size = 0; - elf_tdata (abfd)->eh_frame_hdr = true; + elf_tdata (abfd)->eh_frame_hdr = sec; return true; } @@ -778,21 +704,21 @@ boolean _bfd_elf_maybe_strip_eh_frame_hdr (info) struct bfd_link_info *info; { - asection *sec, *o; + asection *o; bfd *abfd; + struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; - sec = bfd_get_section_by_name (elf_hash_table (info)->dynobj, ".eh_frame_hdr"); - if (sec == NULL || bfd_is_abs_section (sec->output_section)) + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + if (hdr_info->hdr_sec == NULL) return true; - hdr_info - = bfd_zmalloc (sizeof (struct eh_frame_hdr_info)); - if (hdr_info == NULL) - return false; - - elf_section_data (sec)->sec_info = hdr_info; - elf_section_data (sec)->sec_info_type = ELF_INFO_TYPE_EH_FRAME_HDR; + if (bfd_is_abs_section (hdr_info->hdr_sec->output_section)) + { + hdr_info->hdr_sec = NULL; + return true; + } abfd = NULL; if (info->eh_frame_hdr) @@ -807,11 +733,12 @@ _bfd_elf_maybe_strip_eh_frame_hdr (info) if (abfd == NULL) { - _bfd_strip_section_from_output (info, sec); - hdr_info->strip = true; + _bfd_strip_section_from_output (info, hdr_info->hdr_sec); + hdr_info->hdr_sec = NULL; + return true; } - else - hdr_info->table = true; + + hdr_info->table = true; return true; } @@ -869,9 +796,8 @@ _bfd_elf_eh_frame_section_offset (output_bfd, sec, offset) for run-time relocation against LSDA field. */ if (sec_info->entry[mid].make_lsda_relative && ! sec_info->entry[mid].cie - && (offset - == (sec_info->entry[mid].offset + 8 - + sec_info->entry[mid].lsda_offset))) + && (offset == (sec_info->entry[mid].offset + 8 + + sec_info->entry[mid].lsda_offset))) return (bfd_vma) -2; return (offset + sec_info->entry[mid].new_offset @@ -882,12 +808,14 @@ _bfd_elf_eh_frame_section_offset (output_bfd, sec, offset) contents. */ boolean -_bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents) +_bfd_elf_write_section_eh_frame (abfd, info, sec, contents) bfd *abfd; - asection *sec, *ehdrsec; + struct bfd_link_info *info; + asection *sec; bfd_byte *contents; { struct eh_frame_sec_info *sec_info; + struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; unsigned int i; bfd_byte *p, *buf; @@ -905,19 +833,13 @@ _bfd_elf_write_section_eh_frame (abfd, sec, ehdrsec, contents) sec->_raw_size); sec_info = (struct eh_frame_sec_info *) elf_section_data (sec)->sec_info; - hdr_info = NULL; - if (ehdrsec - && (elf_section_data (ehdrsec)->sec_info_type - == ELF_INFO_TYPE_EH_FRAME_HDR)) - { - hdr_info = (struct eh_frame_hdr_info *) - elf_section_data (ehdrsec)->sec_info; - if (hdr_info->table && hdr_info->array == NULL) - hdr_info->array - = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); - if (hdr_info->array == NULL) - hdr_info = NULL; - } + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + if (hdr_info->table && hdr_info->array == NULL) + hdr_info->array + = bfd_malloc (hdr_info->fde_count * sizeof(*hdr_info->array)); + if (hdr_info->array == NULL) + hdr_info = NULL; p = contents; for (i = 0; i < sec_info->count; ++i) @@ -1165,20 +1087,21 @@ vma_compare (a, b) sorted by increasing initial_loc) */ boolean -_bfd_elf_write_section_eh_frame_hdr (abfd, sec) +_bfd_elf_write_section_eh_frame_hdr (abfd, info) bfd *abfd; - asection *sec; + struct bfd_link_info *info; { + struct elf_link_hash_table *htab; struct eh_frame_hdr_info *hdr_info; + asection *sec; bfd_byte *contents; asection *eh_frame_sec; bfd_size_type size; - BFD_ASSERT (elf_section_data (sec)->sec_info_type - == ELF_INFO_TYPE_EH_FRAME_HDR); - hdr_info = (struct eh_frame_hdr_info *) - elf_section_data (sec)->sec_info; - if (hdr_info->strip) + htab = elf_hash_table (info); + hdr_info = &htab->eh_info; + sec = hdr_info->hdr_sec; + if (sec == NULL) return true; size = EH_FRAME_HDR_SIZE; @@ -3449,10 +3449,9 @@ map_sections_to_segments (abfd) /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME segment. */ - eh_frame_hdr = NULL; - if (elf_tdata (abfd)->eh_frame_hdr) - eh_frame_hdr = bfd_get_section_by_name (abfd, ".eh_frame_hdr"); - if (eh_frame_hdr != NULL && (eh_frame_hdr->flags & SEC_LOAD)) + eh_frame_hdr = elf_tdata (abfd)->eh_frame_hdr; + if (eh_frame_hdr != NULL + && (eh_frame_hdr->output_section->flags & SEC_LOAD) != 0) { amt = sizeof (struct elf_segment_map); m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); @@ -3461,7 +3460,7 @@ map_sections_to_segments (abfd) m->next = NULL; m->p_type = PT_GNU_EH_FRAME; m->count = 1; - m->sections[0] = eh_frame_hdr; + m->sections[0] = eh_frame_hdr->output_section; *pm = m; pm = &m->next; @@ -4032,8 +4031,7 @@ get_program_header_size (abfd) ++segs; } - if (elf_tdata (abfd)->eh_frame_hdr - && bfd_get_section_by_name (abfd, ".eh_frame_hdr") != NULL) + if (elf_tdata (abfd)->eh_frame_hdr) { /* We need a PT_GNU_EH_FRAME segment. */ ++segs; @@ -7327,9 +7325,9 @@ _bfd_elf_section_offset (abfd, info, sec, offset) switch (sec_data->sec_info_type) { case ELF_INFO_TYPE_STABS: - return _bfd_stab_section_offset - (abfd, &elf_hash_table (info)->merge_info, sec, &sec_data->sec_info, - offset); + return _bfd_stab_section_offset (abfd, + &elf_hash_table (info)->merge_info, + sec, &sec_data->sec_info, offset); case ELF_INFO_TYPE_EH_FRAME: return _bfd_elf_eh_frame_section_offset (abfd, sec, offset); default: diff --git a/bfd/elflink.h b/bfd/elflink.h index 339cc23..0f59fec 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -2342,6 +2342,7 @@ elf_link_create_dynamic_sections (abfd, info) || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) || ! bfd_set_section_alignment (abfd, s, 2)) return false; + elf_hash_table (info)->eh_info.hdr_sec = s; } /* Create sections to hold version informations. These are removed @@ -5854,17 +5855,10 @@ elf_bfd_final_link (abfd, info) goto error_return; } - if (info->eh_frame_hdr && elf_hash_table (info)->dynobj) + if (info->eh_frame_hdr) { - o = bfd_get_section_by_name (elf_hash_table (info)->dynobj, - ".eh_frame_hdr"); - if (o - && (elf_section_data (o)->sec_info_type - == ELF_INFO_TYPE_EH_FRAME_HDR)) - { - if (! _bfd_elf_write_section_eh_frame_hdr (abfd, o)) - goto error_return; - } + if (! _bfd_elf_write_section_eh_frame_hdr (abfd, info)) + goto error_return; } if (finfo.symstrtab != NULL) @@ -6839,12 +6833,7 @@ elf_link_input_bfd (finfo, input_bfd) from discarded sections and section symbols from removed link-once sections. Complain about relocs against discarded sections. Zero relocs against removed - link-once sections. We should really complain if - anything in the final link tries to use it, but - DWARF-based exception handling might have an entry in - .eh_frame to describe a routine in the linkonce section, - and it turns out to be hard to remove the .eh_frame - entry too. FIXME. */ + link-once sections. */ if (!finfo->info->relocateable && !elf_section_ignore_discarded_relocs (o)) { @@ -7166,19 +7155,14 @@ elf_link_input_bfd (finfo, input_bfd) return false; break; case ELF_INFO_TYPE_MERGE: - if (! (_bfd_write_merged_section - (output_bfd, o, elf_section_data (o)->sec_info))) + if (! _bfd_write_merged_section (output_bfd, o, + elf_section_data (o)->sec_info)) return false; break; case ELF_INFO_TYPE_EH_FRAME: { - asection *ehdrsec; - - ehdrsec - = bfd_get_section_by_name (elf_hash_table (finfo->info)->dynobj, - ".eh_frame_hdr"); - if (! (_bfd_elf_write_section_eh_frame (output_bfd, o, ehdrsec, - contents))) + if (! _bfd_elf_write_section_eh_frame (output_bfd, finfo->info, + o, contents)) return false; } break; @@ -8409,7 +8393,7 @@ elf_bfd_discard_info (output_bfd, info) struct bfd_link_info *info; { struct elf_reloc_cookie cookie; - asection *stab, *eh, *ehdr; + asection *stab, *eh; Elf_Internal_Shdr *symtab_hdr; struct elf_backend_data *bed; bfd *abfd; @@ -8422,11 +8406,6 @@ elf_bfd_discard_info (output_bfd, info) || ! is_elf_hash_table (info)) return false; - ehdr = NULL; - if (elf_hash_table (info)->dynobj != NULL) - ehdr = bfd_get_section_by_name (elf_hash_table (info)->dynobj, - ".eh_frame_hdr"); - for (abfd = info->input_bfds; abfd != NULL; abfd = abfd->link_next) { if (bfd_get_flavour (abfd) != bfd_target_elf_flavour) @@ -8437,15 +8416,11 @@ elf_bfd_discard_info (output_bfd, info) if ((abfd->flags & DYNAMIC) != 0) continue; - eh = NULL; - if (ehdr != NULL) - { - eh = bfd_get_section_by_name (abfd, ".eh_frame"); - if (eh != NULL - && (eh->_raw_size == 0 - || bfd_is_abs_section (eh->output_section))) - eh = NULL; - } + eh = bfd_get_section_by_name (abfd, ".eh_frame"); + if (eh != NULL + && (eh->_raw_size == 0 + || bfd_is_abs_section (eh->output_section))) + eh = NULL; stab = bfd_get_section_by_name (abfd, ".stab"); if (stab != NULL @@ -8520,7 +8495,7 @@ elf_bfd_discard_info (output_bfd, info) if (cookie.rels != NULL) cookie.relend += count * bed->s->int_rels_per_ext_rel; - if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, ehdr, + if (_bfd_elf_discard_section_eh_frame (abfd, info, eh, elf_reloc_symbol_deleted_p, &cookie)) ret = true; @@ -8544,8 +8519,8 @@ elf_bfd_discard_info (output_bfd, info) } } - if (ehdr != NULL - && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info, ehdr)) + if (info->eh_frame_hdr + && _bfd_elf_discard_section_eh_frame_hdr (output_bfd, info)) ret = true; return ret; diff --git a/bfd/po/SRC-POTFILES.in b/bfd/po/SRC-POTFILES.in index b1f7663..e11e314 100644 --- a/bfd/po/SRC-POTFILES.in +++ b/bfd/po/SRC-POTFILES.in @@ -223,6 +223,8 @@ m68klinux.c m68klynx.c m68knetbsd.c m88kmach3.c +mach-o.c +mach-o.h merge.c mipsbsd.c mmo.c @@ -251,6 +253,9 @@ pe-mcore.c pe-mips.c pe-ppc.c pe-sh.c +pef-traceback.h +pef.c +pef.h pei-arm.c pei-i386.c pei-mcore.c @@ -291,3 +296,5 @@ vms.c vms.h xcoff-target.h xcofflink.c +xsym.c +xsym.h |