From: Ian Lance Taylor Date: Tue, 28 Nov 1995 22:02:13 +0000 (+0000) Subject: * elf-bfd.h (struct elf_obj_tdata): Add segment_map field. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fd0198f02371c0d604ec7c3162cf60a0a84c0ef0;p=binutils-gdb.git * elf-bfd.h (struct elf_obj_tdata): Add segment_map field. * elf.c (make_mapping): New static function. (map_sections_to_segments): New static function. (elf_sort_sections): New static function. (assign_file_positions_for_segments): New static function. (map_program_segments): Remove. (get_program_header_size): Remove sorted_hdrs, count, and maxpagesize parameters. Simplify. (assign_file_positions_except_relocs): When generating an executable, use assign_file_positions_for_segments. (elf_sort_hdrs): Remove. (_bfd_elf_sizeof_headers): Remove eliminated parameters from call to get_program_header_size. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 85f39df729b..18e09b5b0ac 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +Tue Nov 28 16:59:50 1995 Ian Lance Taylor + + * elf-bfd.h (struct elf_obj_tdata): Add segment_map field. + * elf.c (make_mapping): New static function. + (map_sections_to_segments): New static function. + (elf_sort_sections): New static function. + (assign_file_positions_for_segments): New static function. + (map_program_segments): Remove. + (get_program_header_size): Remove sorted_hdrs, count, and + maxpagesize parameters. Simplify. + (assign_file_positions_except_relocs): When generating an + executable, use assign_file_positions_for_segments. + (elf_sort_hdrs): Remove. + (_bfd_elf_sizeof_headers): Remove eliminated parameters from call + to get_program_header_size. + Mon Nov 27 12:27:46 1995 Ian Lance Taylor * hp300hpux.c (MY(callback)): Set lma as well as vma. diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h new file mode 100644 index 00000000000..e7baaa9560c --- /dev/null +++ b/bfd/elf-bfd.h @@ -0,0 +1,726 @@ +/* BFD back-end data structures for ELF files. + Copyright (C) 1992, 1993 Free Software Foundation, Inc. + Written by Cygnus Support. + +This file is part of BFD, the Binary File Descriptor library. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _LIBELF_H_ +#define _LIBELF_H_ 1 + +#include "elf/common.h" +#include "elf/internal.h" +#include "elf/external.h" +#include "bfdlink.h" + +/* If size isn't specified as 64 or 32, NAME macro should fail. */ +#ifndef NAME +#if ARCH_SIZE==64 +#define NAME(x,y) CAT4(x,64,_,y) +#endif +#if ARCH_SIZE==32 +#define NAME(x,y) CAT4(x,32,_,y) +#endif +#endif + +#ifndef NAME +#define NAME(x,y) CAT4(x,NOSIZE,_,y) +#endif + +#define ElfNAME(X) NAME(Elf,X) +#define elfNAME(X) NAME(elf,X) + +/* Information held for an ELF symbol. The first field is the + corresponding asymbol. Every symbol is an ELF file is actually a + pointer to this structure, although it is often handled as a + pointer to an asymbol. */ + +typedef struct +{ + /* The BFD symbol. */ + asymbol symbol; + /* ELF symbol information. */ + Elf_Internal_Sym internal_elf_sym; + /* Backend specific information. */ + union + { + unsigned int hppa_arg_reloc; + PTR mips_extr; + PTR any; + } + tc_data; +} elf_symbol_type; + +/* ELF linker hash table entries. */ + +struct elf_link_hash_entry +{ + struct bfd_link_hash_entry root; + + /* Symbol index in output file. This is initialized to -1. It is + set to -2 if the symbol is used by a reloc. */ + long indx; + + /* Symbol size. */ + bfd_size_type size; + + /* Symbol index as a dynamic symbol. Initialized to -1, and remains + -1 if this is not a dynamic symbol. */ + long dynindx; + + /* String table index in .dynstr if this is a dynamic symbol. */ + unsigned long dynstr_index; + + /* If this is a weak defined symbol from a dynamic object, this + field points to a defined symbol with the same value, if there is + one. Otherwise it is NULL. */ + struct elf_link_hash_entry *weakdef; + + /* If this symbol requires an entry in the global offset table, the + processor specific backend uses this field to hold the offset + into the .got section. If this field is -1, then the symbol does + not require a global offset table entry. */ + bfd_vma got_offset; + + /* If this symbol requires an entry in the procedure linkage table, + the processor specific backend uses these two fields to hold the + offset into the procedure linkage section and the offset into the + .got section. If plt_offset is -1, then the symbol does not + require an entry in the procedure linkage table. */ + bfd_vma plt_offset; + + /* Symbol type (STT_NOTYPE, STT_OBJECT, etc.). */ + char type; + + /* Some flags; legal values follow. */ + unsigned char elf_link_hash_flags; + /* Symbol is referenced by a non-shared object. */ +#define ELF_LINK_HASH_REF_REGULAR 01 + /* Symbol is defined by a non-shared object. */ +#define ELF_LINK_HASH_DEF_REGULAR 02 + /* Symbol is referenced by a shared object. */ +#define ELF_LINK_HASH_REF_DYNAMIC 04 + /* Symbol is defined by a shared object. */ +#define ELF_LINK_HASH_DEF_DYNAMIC 010 + /* Dynamic symbol has been adjustd. */ +#define ELF_LINK_HASH_DYNAMIC_ADJUSTED 020 + /* Symbol needs a copy reloc. */ +#define ELF_LINK_HASH_NEEDS_COPY 040 + /* Symbol needs a procedure linkage table entry. */ +#define ELF_LINK_HASH_NEEDS_PLT 0100 +}; + +/* ELF linker hash table. */ + +struct elf_link_hash_table +{ + struct bfd_link_hash_table root; + /* Whether we have created the special dynamic sections required + when linking against or generating a shared object. */ + boolean dynamic_sections_created; + /* The BFD used to hold special sections created by the linker. + This will be the first BFD found which requires these sections to + be created. */ + bfd *dynobj; + /* The number of symbols found in the link which must be put into + the .dynsym section. */ + bfd_size_type dynsymcount; + /* The string table of dynamic symbols, which becomes the .dynstr + section. */ + struct bfd_strtab_hash *dynstr; + /* The number of buckets in the hash table in the .hash section. + This is based on the number of dynamic symbols. */ + bfd_size_type bucketcount; + /* A linked list of DT_NEEDED names found in dynamic objects + included in the link. */ + struct bfd_link_needed_list *needed; +}; + +/* Look up an entry in an ELF linker hash table. */ + +#define elf_link_hash_lookup(table, string, create, copy, follow) \ + ((struct elf_link_hash_entry *) \ + bfd_link_hash_lookup (&(table)->root, (string), (create), \ + (copy), (follow))) + +/* Traverse an ELF linker hash table. */ + +#define elf_link_hash_traverse(table, func, info) \ + (bfd_link_hash_traverse \ + (&(table)->root, \ + (boolean (*) PARAMS ((struct bfd_link_hash_entry *, PTR))) (func), \ + (info))) + +/* Get the ELF linker hash table from a link_info structure. */ + +#define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash)) + +/* Constant information held for an ELF backend. */ + +struct elf_size_info { + unsigned char sizeof_ehdr, sizeof_phdr, sizeof_shdr; + unsigned char sizeof_rel, sizeof_rela, sizeof_sym, sizeof_dyn, sizeof_note; + + unsigned char arch_size, file_align; + unsigned char elfclass, ev_current; + int (*write_out_phdrs) PARAMS ((bfd *, Elf_Internal_Phdr *, int)); + boolean (*write_shdrs_and_ehdr) PARAMS ((bfd *)); + void (*write_relocs) PARAMS ((bfd *, asection *, PTR)); + void (*swap_symbol_out) PARAMS ((bfd *, Elf_Internal_Sym *, PTR)); + boolean (*slurp_reloc_table) PARAMS ((bfd *, asection *, asymbol **)); + long (*slurp_symbol_table) PARAMS ((bfd *, asymbol **, boolean)); +}; + +#define elf_symbol_from(ABFD,S) \ + (((S)->the_bfd->xvec->flavour == bfd_target_elf_flavour \ + && (S)->the_bfd->tdata.elf_obj_data != 0) \ + ? (elf_symbol_type *) (S) \ + : 0) + +struct elf_backend_data +{ + /* Whether the backend uses REL or RELA relocations. FIXME: some + ELF backends use both. When we need to support one, this whole + approach will need to be changed. */ + int use_rela_p; + + /* The architecture for this backend. */ + enum bfd_architecture arch; + + /* The ELF machine code (EM_xxxx) for this backend. */ + int elf_machine_code; + + /* The maximum page size for this backend. */ + bfd_vma maxpagesize; + + /* This is true if the linker should act like collect and gather + global constructors and destructors by name. This is true for + MIPS ELF because the Irix 5 tools can not handle the .init + section. */ + boolean collect; + + /* A function to translate an ELF RELA relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto) PARAMS ((bfd *, arelent *, + Elf_Internal_Rela *)); + + /* A function to translate an ELF REL relocation to a BFD arelent + structure. */ + void (*elf_info_to_howto_rel) PARAMS ((bfd *, arelent *, + Elf_Internal_Rel *)); + + /* A function to determine whether a symbol is global when + partitioning the symbol table into local and global symbols. + This should be NULL for most targets, in which case the correct + thing will be done. MIPS ELF, at least on the Irix 5, has + special requirements. */ + boolean (*elf_backend_sym_is_global) PARAMS ((bfd *, asymbol *)); + + /* The remaining functions are hooks which are called only if they + are not NULL. */ + + /* A function to permit a backend specific check on whether a + particular BFD format is relevant for an object file, and to + permit the backend to set any global information it wishes. When + this is called elf_elfheader is set, but anything else should be + used with caution. If this returns false, the check_format + routine will return a bfd_error_wrong_format error. */ + boolean (*elf_backend_object_p) PARAMS ((bfd *)); + + /* A function to do additional symbol processing when reading the + ELF symbol table. This is where any processor-specific special + section indices are handled. */ + void (*elf_backend_symbol_processing) PARAMS ((bfd *, asymbol *)); + + /* A function to do additional symbol processing after reading the + entire ELF symbol table. */ + boolean (*elf_backend_symbol_table_processing) PARAMS ((bfd *, + elf_symbol_type *, + unsigned int)); + + /* A function to do additional processing on the ELF section header + just before writing it out. This is used to set the flags and + type fields for some sections, or to actually write out data for + unusual sections. */ + boolean (*elf_backend_section_processing) PARAMS ((bfd *, + Elf32_Internal_Shdr *)); + + /* A function to handle unusual section types when creating BFD + sections from ELF sections. */ + boolean (*elf_backend_section_from_shdr) PARAMS ((bfd *, + Elf32_Internal_Shdr *, + char *)); + + /* A function to set up the ELF section header for a BFD section in + preparation for writing it out. This is where the flags and type + fields are set for unusual sections. */ + boolean (*elf_backend_fake_sections) PARAMS ((bfd *, Elf32_Internal_Shdr *, + asection *)); + + /* A function to get the ELF section index for a BFD section. If + this returns true, the section was found. If it is a normal ELF + section, *RETVAL should be left unchanged. If it is not a normal + ELF section *RETVAL should be set to the SHN_xxxx index. */ + boolean (*elf_backend_section_from_bfd_section) + PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *retval)); + + /* If this field is not NULL, it is called by the add_symbols phase + of a link just before adding a symbol to the global linker hash + table. It may modify any of the fields as it wishes. If *NAME + is set to NULL, the symbol will be skipped rather than being + added to the hash table. This function is responsible for + handling all processor dependent symbol bindings and section + indices, and must set at least *FLAGS and *SEC for each processor + dependent case; failure to do so will cause a link error. */ + boolean (*elf_add_symbol_hook) + PARAMS ((bfd *abfd, struct bfd_link_info *info, + const Elf_Internal_Sym *, const char **name, + flagword *flags, asection **sec, bfd_vma *value)); + + /* If this field is not NULL, it is called by the elf_link_output_sym + phase of a link for each symbol which will appear in the object file. */ + boolean (*elf_backend_link_output_symbol_hook) + PARAMS ((bfd *, struct bfd_link_info *info, const char *, + Elf_Internal_Sym *, asection *)); + + /* The CREATE_DYNAMIC_SECTIONS function is called by the ELF backend + linker the first time it encounters a dynamic object in the link. + This function must create any sections required for dynamic + linking. The ABFD argument is a dynamic object. The .interp, + .dynamic, .dynsym, .dynstr, and .hash functions have already been + created, and this function may modify the section flags if + desired. This function will normally create the .got and .plt + sections, but different backends have different requirements. */ + boolean (*elf_backend_create_dynamic_sections) + PARAMS ((bfd *abfd, struct bfd_link_info *info)); + + /* The CHECK_RELOCS function is called by the add_symbols phase of + the ELF backend linker. It is called once for each section with + relocs of an object file, just after the symbols for the object + file have been added to the global linker hash table. The + function must look through the relocs and do any special handling + required. This generally means allocating space in the global + offset table, and perhaps allocating space for a reloc. The + relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. */ + boolean (*check_relocs) + PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *o, + const Elf_Internal_Rela *relocs)); + + /* The ADJUST_DYNAMIC_SYMBOL function is called by the ELF backend + linker for every symbol which is defined by a dynamic object and + referenced by a regular object. This is called after all the + input files have been seen, but before the SIZE_DYNAMIC_SECTIONS + function has been called. The hash table entry should be + bfd_link_hash_defined ore bfd_link_hash_defweak, and it should be + defined in a section from a dynamic object. Dynamic object + sections are not included in the final link, and this function is + responsible for changing the value to something which the rest of + the link can deal with. This will normally involve adding an + entry to the .plt or .got or some such section, and setting the + symbol to point to that. */ + boolean (*elf_backend_adjust_dynamic_symbol) + PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h)); + + /* The SIZE_DYNAMIC_SECTIONS function is called by the ELF backend + linker after all the linker input files have been seen but before + the sections sizes have been set. This is called after + ADJUST_DYNAMIC_SYMBOL has been called on all appropriate symbols. + It is only called when linking against a dynamic object. It must + set the sizes of the dynamic sections, and may fill in their + contents as well. The generic ELF linker can handle the .dynsym, + .dynstr and .hash sections. This function must handle the + .interp section and any sections created by the + CREATE_DYNAMIC_SECTIONS entry point. */ + boolean (*elf_backend_size_dynamic_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* The RELOCATE_SECTION function is called by the ELF backend linker + to handle the relocations for a section. + + The relocs are always passed as Rela structures; if the section + actually uses Rel structures, the r_addend field will always be + zero. + + This function is responsible for adjust the section contents as + necessary, and (if using Rela relocs and generating a + relocateable output file) adjusting the reloc addend as + necessary. + + This function does not have to worry about setting the reloc + address or the reloc symbol index. + + LOCAL_SYMS is a pointer to the swapped in local symbols. + + LOCAL_SECTIONS is an array giving the section in the input file + corresponding to the st_shndx field of each local symbol. + + The global hash table entry for the global symbols can be found + via elf_sym_hashes (input_bfd). + + When generating relocateable output, this function must handle + STB_LOCAL/STT_SECTION symbols specially. The output symbol is + going to be the section symbol corresponding to the output + section, which means that the addend must be adjusted + accordingly. */ + boolean (*elf_backend_relocate_section) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info, + bfd *input_bfd, asection *input_section, bfd_byte *contents, + Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms, + asection **local_sections)); + + /* The FINISH_DYNAMIC_SYMBOL function is called by the ELF backend + linker just before it writes a symbol out to the .dynsym section. + The processor backend may make any required adjustment to the + symbol. It may also take the opportunity to set contents of the + dynamic sections. Note that FINISH_DYNAMIC_SYMBOL is called on + all .dynsym symbols, while ADJUST_DYNAMIC_SYMBOL is only called + on those symbols which are defined by a dynamic object. */ + boolean (*elf_backend_finish_dynamic_symbol) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info, + struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)); + + /* The FINISH_DYNAMIC_SECTIONS function is called by the ELF backend + linker just before it writes all the dynamic sections out to the + output file. The FINISH_DYNAMIC_SYMBOL will have been called on + all dynamic symbols. */ + boolean (*elf_backend_finish_dynamic_sections) + PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); + + /* A function to do any beginning processing needed for the ELF file + before building the ELF headers and computing file positions. */ + void (*elf_backend_begin_write_processing) + PARAMS ((bfd *, struct bfd_link_info *)); + + /* A function to do any final processing needed for the ELF file + before writing it out. The LINKER argument is true if this BFD + was created by the ELF backend linker. */ + void (*elf_backend_final_write_processing) + PARAMS ((bfd *, boolean linker)); + + /* A function to create any special program headers required by the + backend. PHDRS are the program headers, and PHDR_COUNT is the + number of them. If PHDRS is NULL, this just counts headers + without creating them. This returns an updated value for + PHDR_COUNT. */ + int (*elf_backend_create_program_headers) + PARAMS ((bfd *, Elf_Internal_Phdr *phdrs, int phdr_count)); + + /* The swapping table to use when dealing with ECOFF information. + Used for the MIPS ELF .mdebug section. */ + const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap; + + /* Alternate EM_xxxx machine codes for this backend. */ + int elf_machine_alt1; + int elf_machine_alt2; + + const struct elf_size_info *s; + + unsigned want_got_plt : 1; + unsigned plt_readonly : 1; + unsigned want_plt_sym : 1; + + /* Put ELF and program headers in the first loadable segment. */ + unsigned want_hdr_in_seg : 1; +}; + +/* Information stored for each BFD section in an ELF file. This + structure is allocated by elf_new_section_hook. */ + +struct bfd_elf_section_data { + /* The ELF header for this section. */ + Elf_Internal_Shdr this_hdr; + /* The ELF header for the reloc section associated with this + section, if any. */ + Elf_Internal_Shdr rel_hdr; + /* The ELF section number of this section. Only used for an output + file. */ + int this_idx; + /* The ELF section number of the reloc section associated with this + section, if any. Only used for an output file. */ + int rel_idx; + /* Used by the backend linker to store the symbol hash table entries + associated with relocs against global symbols. */ + struct elf_link_hash_entry **rel_hashes; + /* A pointer to the swapped relocs. If the section uses REL relocs, + rather than RELA, all the r_addend fields will be zero. This + pointer may be NULL. It is used by the backend linker. */ + Elf_Internal_Rela *relocs; + /* Used by the backend linker when generating a shared library to + record the dynamic symbol index for a section symbol + corresponding to this section. */ + long dynindx; +}; + +#define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd) + +#define get_elf_backend_data(abfd) \ + ((struct elf_backend_data *) (abfd)->xvec->backend_data) + +/* Some private data is stashed away for future use using the tdata pointer + in the bfd structure. */ + +struct elf_obj_tdata +{ + Elf_Internal_Ehdr elf_header[1]; /* Actual data, but ref like ptr */ + Elf_Internal_Shdr **elf_sect_ptr; + Elf_Internal_Phdr *phdr; + struct elf_segment_map *segment_map; + struct bfd_strtab_hash *strtab_ptr; + int num_locals; + int num_globals; + asymbol **section_syms; /* STT_SECTION symbols for each section */ + Elf_Internal_Shdr symtab_hdr; + Elf_Internal_Shdr shstrtab_hdr; + Elf_Internal_Shdr strtab_hdr; + Elf_Internal_Shdr dynsymtab_hdr; + Elf_Internal_Shdr dynstrtab_hdr; + unsigned int symtab_section, shstrtab_section; + unsigned int strtab_section, dynsymtab_section; + file_ptr next_file_pos; + void *prstatus; /* The raw /proc prstatus structure */ + void *prpsinfo; /* The raw /proc prpsinfo structure */ + bfd_vma gp; /* The gp value (MIPS only, for now) */ + unsigned int gp_size; /* The gp size (MIPS only, for now) */ + + /* This is set to true if the object was created by the backend + linker. */ + boolean linker; + + /* A mapping from external symbols to entries in the linker hash + table, used when linking. This is indexed by the symbol index + minus the sh_info field of the symbol table header. */ + struct elf_link_hash_entry **sym_hashes; + + /* A mapping from local symbols to offsets into the global offset + table, used when linking. This is indexed by the symbol index. */ + bfd_vma *local_got_offsets; + + /* The linker ELF emulation code needs to let the backend ELF linker + know what filename should be used for a dynamic object if the + dynamic object is found using a search. This field is used to + hold that information. */ + const char *dt_needed_name; + + /* Irix 5 often screws up the symbol table, sorting local symbols + after global symbols. This flag is set if the symbol table in + this BFD appears to be screwed up. If it is, we ignore the + sh_info field in the symbol table header, and always read all the + symbols. */ + boolean bad_symtab; + + /* Records the result of `get_program_header_size'. */ + bfd_size_type program_header_size; + + /* Used by MIPS ELF find_nearest_line entry point. The structure + could be included directly in this one, but there's no point to + wasting the memory just for the infrequently called + find_nearest_line. */ + struct mips_elf_find_line *find_line_info; + + /* Used by PowerPC to determine if the e_flags field has been intiialized */ + boolean ppc_flags_init; +}; + +#define elf_tdata(bfd) ((bfd) -> tdata.elf_obj_data) +#define elf_elfheader(bfd) (elf_tdata(bfd) -> elf_header) +#define elf_elfsections(bfd) (elf_tdata(bfd) -> elf_sect_ptr) +#define elf_shstrtab(bfd) (elf_tdata(bfd) -> strtab_ptr) +#define elf_onesymtab(bfd) (elf_tdata(bfd) -> symtab_section) +#define elf_dynsymtab(bfd) (elf_tdata(bfd) -> dynsymtab_section) +#define elf_num_locals(bfd) (elf_tdata(bfd) -> num_locals) +#define elf_num_globals(bfd) (elf_tdata(bfd) -> num_globals) +#define elf_section_syms(bfd) (elf_tdata(bfd) -> section_syms) +#define core_prpsinfo(bfd) (elf_tdata(bfd) -> prpsinfo) +#define core_prstatus(bfd) (elf_tdata(bfd) -> prstatus) +#define elf_gp(bfd) (elf_tdata(bfd) -> gp) +#define elf_gp_size(bfd) (elf_tdata(bfd) -> gp_size) +#define elf_sym_hashes(bfd) (elf_tdata(bfd) -> sym_hashes) +#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got_offsets) +#define elf_dt_needed_name(bfd) (elf_tdata(bfd) -> dt_needed_name) +#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab) +#define elf_ppc_flags_init(bfd) (elf_tdata(bfd) -> ppc_flags_init) + +extern char * bfd_elf_string_from_elf_section PARAMS ((bfd *, unsigned, unsigned)); +extern char * bfd_elf_get_str_section PARAMS ((bfd *, unsigned)); + +extern void bfd_elf_print_symbol PARAMS ((bfd *, PTR, asymbol *, + bfd_print_symbol_type)); +#define elf_string_from_elf_strtab(abfd,strindex) \ + bfd_elf_string_from_elf_section(abfd,elf_elfheader(abfd)->e_shstrndx,strindex) + +#define bfd_elf32_print_symbol bfd_elf_print_symbol +#define bfd_elf64_print_symbol bfd_elf_print_symbol +#define bfd_elf32_mkobject bfd_elf_mkobject +#define bfd_elf64_mkobject bfd_elf_mkobject +#define elf_mkobject bfd_elf_mkobject + +extern unsigned long bfd_elf_hash PARAMS ((CONST unsigned char *)); + +extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *, + arelent *, + asymbol *, + PTR, + asection *, + bfd *, + char **)); +extern boolean bfd_elf_mkobject PARAMS ((bfd *)); +extern Elf_Internal_Shdr *bfd_elf_find_section PARAMS ((bfd *, char *)); +extern boolean _bfd_elf_make_section_from_shdr + PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, const char *name)); +extern struct bfd_hash_entry *_bfd_elf_link_hash_newfunc + PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); +extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create + PARAMS ((bfd *)); +extern boolean _bfd_elf_link_hash_table_init + PARAMS ((struct elf_link_hash_table *, bfd *, + struct bfd_hash_entry *(*) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *))); + +extern boolean _bfd_elf_copy_private_symbol_data + PARAMS ((bfd *, asymbol *, bfd *, asymbol *)); +extern boolean _bfd_elf_copy_private_section_data + PARAMS ((bfd *, asection *, bfd *, asection *)); +extern boolean _bfd_elf_write_object_contents PARAMS ((bfd *)); +extern boolean _bfd_elf_set_section_contents PARAMS ((bfd *, sec_ptr, PTR, + file_ptr, + bfd_size_type)); +extern long _bfd_elf_get_symtab_upper_bound PARAMS ((bfd *)); +extern long _bfd_elf_get_symtab PARAMS ((bfd *, asymbol **)); +extern long _bfd_elf_get_dynamic_symtab_upper_bound PARAMS ((bfd *)); +extern long _bfd_elf_canonicalize_dynamic_symtab PARAMS ((bfd *, asymbol **)); +extern long _bfd_elf_get_reloc_upper_bound PARAMS ((bfd *, sec_ptr)); +extern long _bfd_elf_canonicalize_reloc PARAMS ((bfd *, sec_ptr, + arelent **, asymbol **)); +extern asymbol *_bfd_elf_make_empty_symbol PARAMS ((bfd *)); +extern void _bfd_elf_get_symbol_info PARAMS ((bfd *, asymbol *, + symbol_info *)); +extern alent *_bfd_elf_get_lineno PARAMS ((bfd *, asymbol *)); +extern boolean _bfd_elf_set_arch_mach PARAMS ((bfd *, enum bfd_architecture, + unsigned long)); +extern boolean _bfd_elf_find_nearest_line PARAMS ((bfd *, asection *, + asymbol **, + bfd_vma, CONST char **, + CONST char **, + unsigned int *)); +#define _bfd_elf_read_minisymbols _bfd_generic_read_minisymbols +#define _bfd_elf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol +extern int _bfd_elf_sizeof_headers PARAMS ((bfd *, boolean)); +extern boolean _bfd_elf_new_section_hook PARAMS ((bfd *, asection *)); + +/* If the target doesn't have reloc handling written yet: */ +extern void _bfd_elf_no_info_to_howto PARAMS ((bfd *, arelent *, + Elf_Internal_Rela *)); + +asection *bfd_section_from_elf_index PARAMS ((bfd *, unsigned int)); +boolean _bfd_elf_create_dynamic_sections PARAMS ((bfd *, + struct bfd_link_info *)); +struct bfd_strtab_hash *_bfd_elf_stringtab_init PARAMS ((void)); +boolean +_bfd_elf_link_record_dynamic_symbol PARAMS ((struct bfd_link_info *, + struct elf_link_hash_entry *)); +boolean +_bfd_elf_compute_section_file_positions PARAMS ((bfd *, + struct bfd_link_info *)); +void _bfd_elf_assign_file_positions_for_relocs PARAMS ((bfd *)); +file_ptr _bfd_elf_assign_file_position_for_section PARAMS ((Elf_Internal_Shdr *, + file_ptr, + boolean)); + +boolean _bfd_elf_create_dynamic_sections PARAMS ((bfd *, + struct bfd_link_info *)); +boolean _bfd_elf_create_got_section PARAMS ((bfd *, + struct bfd_link_info *)); + +extern const bfd_target *bfd_elf32_object_p PARAMS ((bfd *)); +extern const bfd_target *bfd_elf32_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf32_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf32_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf32_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); + +extern boolean bfd_elf32_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf32_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern void bfd_elf32_swap_symbol_in + PARAMS ((bfd *, Elf32_External_Sym *, Elf_Internal_Sym *)); +extern void bfd_elf32_swap_symbol_out + PARAMS ((bfd *, Elf_Internal_Sym *, PTR)); +extern void bfd_elf32_swap_reloc_in + PARAMS ((bfd *, Elf32_External_Rel *, Elf_Internal_Rel *)); +extern void bfd_elf32_swap_reloc_out + PARAMS ((bfd *, Elf_Internal_Rel *, Elf32_External_Rel *)); +extern void bfd_elf32_swap_reloca_in + PARAMS ((bfd *, Elf32_External_Rela *, Elf_Internal_Rela *)); +extern void bfd_elf32_swap_reloca_out + PARAMS ((bfd *, Elf_Internal_Rela *, Elf32_External_Rela *)); +extern void bfd_elf32_swap_phdr_in + PARAMS ((bfd *, Elf32_External_Phdr *, Elf_Internal_Phdr *)); +extern void bfd_elf32_swap_phdr_out + PARAMS ((bfd *, Elf_Internal_Phdr *, Elf32_External_Phdr *)); +extern void bfd_elf32_swap_dyn_in + PARAMS ((bfd *, const Elf32_External_Dyn *, Elf_Internal_Dyn *)); +extern void bfd_elf32_swap_dyn_out + PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf32_External_Dyn *)); +extern boolean bfd_elf32_add_dynamic_entry + PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma)); +extern boolean bfd_elf32_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +extern const bfd_target *bfd_elf64_object_p PARAMS ((bfd *)); +extern const bfd_target *bfd_elf64_core_file_p PARAMS ((bfd *)); +extern char *bfd_elf64_core_file_failing_command PARAMS ((bfd *)); +extern int bfd_elf64_core_file_failing_signal PARAMS ((bfd *)); +extern boolean bfd_elf64_core_file_matches_executable_p PARAMS ((bfd *, + bfd *)); +extern boolean bfd_elf64_bfd_link_add_symbols + PARAMS ((bfd *, struct bfd_link_info *)); +extern boolean bfd_elf64_bfd_final_link + PARAMS ((bfd *, struct bfd_link_info *)); + +extern void bfd_elf64_swap_symbol_in + PARAMS ((bfd *, Elf64_External_Sym *, Elf_Internal_Sym *)); +extern void bfd_elf64_swap_symbol_out + PARAMS ((bfd *, Elf_Internal_Sym *, PTR)); +extern void bfd_elf64_swap_reloc_in + PARAMS ((bfd *, Elf64_External_Rel *, Elf_Internal_Rel *)); +extern void bfd_elf64_swap_reloc_out + PARAMS ((bfd *, Elf_Internal_Rel *, Elf64_External_Rel *)); +extern void bfd_elf64_swap_reloca_in + PARAMS ((bfd *, Elf64_External_Rela *, Elf_Internal_Rela *)); +extern void bfd_elf64_swap_reloca_out + PARAMS ((bfd *, Elf_Internal_Rela *, Elf64_External_Rela *)); +extern void bfd_elf64_swap_phdr_in + PARAMS ((bfd *, Elf64_External_Phdr *, Elf_Internal_Phdr *)); +extern void bfd_elf64_swap_phdr_out + PARAMS ((bfd *, Elf_Internal_Phdr *, Elf64_External_Phdr *)); +extern void bfd_elf64_swap_dyn_in + PARAMS ((bfd *, const Elf64_External_Dyn *, Elf_Internal_Dyn *)); +extern void bfd_elf64_swap_dyn_out + PARAMS ((bfd *, const Elf_Internal_Dyn *, Elf64_External_Dyn *)); +extern boolean bfd_elf64_add_dynamic_entry + PARAMS ((struct bfd_link_info *, bfd_vma, bfd_vma)); +extern boolean bfd_elf64_link_create_dynamic_sections + PARAMS ((bfd *, struct bfd_link_info *)); + +#define bfd_elf32_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol +#define bfd_elf64_link_record_dynamic_symbol _bfd_elf_link_record_dynamic_symbol + +#endif /* _LIBELF_H_ */ diff --git a/bfd/elf.c b/bfd/elf.c index 95245f54732..083f8d2c07b 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -38,11 +38,11 @@ SECTION #define ARCH_SIZE 0 #include "elf-bfd.h" -static file_ptr map_program_segments PARAMS ((bfd *, file_ptr, - Elf_Internal_Shdr *, - Elf_Internal_Shdr **, - bfd_size_type)); -static boolean assign_file_positions_except_relocs PARAMS ((bfd *, boolean)); +static INLINE struct elf_segment_map *make_mapping + PARAMS ((bfd *, asection **, unsigned int, unsigned int)); +static int elf_sort_sections PARAMS ((const PTR, const PTR)); +static boolean assign_file_positions_for_segments PARAMS ((bfd *)); +static boolean assign_file_positions_except_relocs PARAMS ((bfd *)); static boolean prep_headers PARAMS ((bfd *)); static boolean swap_out_syms PARAMS ((bfd *, struct bfd_strtab_hash **)); @@ -219,6 +219,26 @@ _bfd_elf_make_section_from_shdr (abfd, hdr, name) if (! bfd_set_section_flags (abfd, newsect, flags)) return false; + if ((flags & SEC_ALLOC) != 0) + { + Elf_Internal_Phdr *phdr; + unsigned int i; + + /* Look through the phdrs to see if we need to adjust the lma. */ + phdr = elf_tdata (abfd)->phdr; + for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) + { + if (phdr->p_type == PT_LOAD + && phdr->p_vaddr != phdr->p_paddr + && phdr->p_vaddr <= hdr->sh_addr + && phdr->p_vaddr + phdr->p_memsz >= hdr->sh_addr + hdr->sh_size) + { + newsect->lma += phdr->p_paddr - phdr->p_vaddr; + break; + } + } + } + hdr->bfd_section = newsect; elf_section_data (newsect)->this_hdr = *hdr; @@ -521,7 +541,7 @@ bfd_section_from_shdr (abfd, shindex) BFD_ASSERT (elf_onesymtab (abfd) == 0); elf_onesymtab (abfd) = shindex; elf_tdata (abfd)->symtab_hdr = *hdr; - elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->symtab_hdr; + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->symtab_hdr; abfd->flags |= HAS_SYMS; /* Sometimes a shared object will map in the symbol table. If @@ -545,7 +565,7 @@ bfd_section_from_shdr (abfd, shindex) BFD_ASSERT (elf_dynsymtab (abfd) == 0); elf_dynsymtab (abfd) = shindex; elf_tdata (abfd)->dynsymtab_hdr = *hdr; - elf_elfsections (abfd)[shindex] = &elf_tdata (abfd)->dynsymtab_hdr; + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynsymtab_hdr; abfd->flags |= HAS_SYMS; /* Besides being a symbol table, we also treat this as a regular @@ -581,7 +601,7 @@ bfd_section_from_shdr (abfd, shindex) if (elf_dynsymtab (abfd) == i) { elf_tdata (abfd)->dynstrtab_hdr = *hdr; - elf_elfsections (abfd)[shindex] = + elf_elfsections (abfd)[shindex] = hdr = &elf_tdata (abfd)->dynstrtab_hdr; /* We also treat this as a regular section, so that objcopy can handle it. */ @@ -867,27 +887,17 @@ elf_fake_sections (abfd, asect, failedptrarg) this_hdr->sh_flags = 0; - /* FIXME: This should really use vma, rather than lma. However, - that would mean that the lma information was lost, which would - mean that the AT keyword in linker scripts would not work. - Fortunately, native scripts do not use the AT keyword, so we can - get away with using lma here. The right way to handle this is to - 1) read the program headers as well as the section headers, and - set the lma fields of the BFD sections based on the p_paddr - fields of the program headers, and 2) set the p_paddr fields of - the program headers based on the section lma fields when writing - them out. */ if ((asect->flags & SEC_ALLOC) != 0) - this_hdr->sh_addr = asect->lma; + this_hdr->sh_addr = asect->vma; else this_hdr->sh_addr = 0; this_hdr->sh_offset = 0; this_hdr->sh_size = asect->_raw_size; this_hdr->sh_link = 0; - this_hdr->sh_info = 0; this_hdr->sh_addralign = 1 << asect->alignment_power; - this_hdr->sh_entsize = 0; + /* The sh_entsize and sh_info fields may have been set already by + copy_private_section_data. */ this_hdr->bfd_section = asect; this_hdr->contents = NULL; @@ -1220,7 +1230,7 @@ elf_map_symbols (abfd) for (idx = 0; idx < symcount; idx++) { if ((syms[idx]->flags & BSF_SECTION_SYM) != 0 - && syms[idx]->value == 0) + && (syms[idx]->value + syms[idx]->section->vma) == 0) { asection *sec; @@ -1333,6 +1343,43 @@ elf_map_symbols (abfd) return true; } +/* Align to the maximum file alignment that could be required for any + ELF data structure. */ + +static INLINE file_ptr align_file_position PARAMS ((file_ptr, int)); +static INLINE file_ptr +align_file_position (off, align) + file_ptr off; + int align; +{ + return (off + align - 1) & ~(align - 1); +} + +/* Assign a file position to a section, optionally aligning to the + required section alignment. */ + +INLINE file_ptr +_bfd_elf_assign_file_position_for_section (i_shdrp, offset, align) + Elf_Internal_Shdr *i_shdrp; + file_ptr offset; + boolean align; +{ + if (align) + { + unsigned int al; + + al = i_shdrp->sh_addralign; + if (al > 1) + offset = BFD_ALIGN (offset, al); + } + i_shdrp->sh_offset = offset; + if (i_shdrp->bfd_section != NULL) + i_shdrp->bfd_section->filepos = offset; + if (i_shdrp->sh_type != SHT_NOBITS) + offset += i_shdrp->sh_size; + return offset; +} + /* Compute the file positions we are going to put the sections at, and otherwise prepare to begin writing out the ELF file. If LINK_INFO is not NULL, this is being called by the ELF backend linker. */ @@ -1366,7 +1413,7 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) return false; /* The backend linker builds symbol table information itself. */ - if (link_info == NULL) + if (link_info == NULL && abfd->symcount > 0) { if (! swap_out_syms (abfd, &strtab)) return false; @@ -1381,19 +1428,30 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) shstrtab_hdr->sh_entsize = 0; shstrtab_hdr->sh_link = 0; shstrtab_hdr->sh_info = 0; - /* sh_offset is set in assign_file_positions_for_symtabs_and_strtabs. */ + /* sh_offset is set in assign_file_positions_except_relocs. */ shstrtab_hdr->sh_addralign = 1; - if (!assign_file_positions_except_relocs (abfd, - link_info == NULL ? true : false)) + if (!assign_file_positions_except_relocs (abfd)) return false; - if (link_info == NULL) + if (link_info == NULL && abfd->symcount > 0) { + file_ptr off; + Elf_Internal_Shdr *hdr; + + off = elf_tdata (abfd)->next_file_pos; + + hdr = &elf_tdata (abfd)->symtab_hdr; + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + + hdr = &elf_tdata (abfd)->strtab_hdr; + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + + elf_tdata (abfd)->next_file_pos = off; + /* Now that we know where the .strtab section goes, write it out. */ - if ((bfd_seek (abfd, elf_tdata (abfd)->strtab_hdr.sh_offset, SEEK_SET) - != 0) + if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 || ! _bfd_stringtab_emit (abfd, strtab)) return false; _bfd_stringtab_free (strtab); @@ -1404,428 +1462,542 @@ _bfd_elf_compute_section_file_positions (abfd, link_info) return true; } +/* Create a mapping from a set of sections to a program segment. */ -/* Align to the maximum file alignment that could be required for any - ELF data structure. */ - -static INLINE file_ptr align_file_position PARAMS ((file_ptr, int)); -static INLINE file_ptr -align_file_position (off, align) - file_ptr off; - int align; +static INLINE struct elf_segment_map * +make_mapping (abfd, sections, from, to) + bfd *abfd; + asection **sections; + unsigned int from; + unsigned int to; { - return (off + align - 1) & ~(align - 1); + struct elf_segment_map *m; + unsigned int i; + asection **hdrpp; + + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, + (sizeof (struct elf_segment_map) + + (to - from - 1) * sizeof (asection *)))); + if (m == NULL) + { + bfd_set_error (bfd_error_no_memory); + return NULL; + } + m->next = NULL; + m->p_type = PT_LOAD; + for (i = from, hdrpp = sections + from; i < to; i++, hdrpp++) + m->sections[i - from] = *hdrpp; + m->count = to - from; + + return m; } -/* Assign a file position to a section, optionally aligning to the - required section alignment. */ +/* Set up a mapping from BFD sections to program segments. */ -INLINE file_ptr -_bfd_elf_assign_file_position_for_section (i_shdrp, offset, align) - Elf_Internal_Shdr *i_shdrp; - file_ptr offset; - boolean align; +static boolean +map_sections_to_segments (abfd) + bfd *abfd; { - if (align) + asection **sections = NULL; + asection *s; + unsigned int i; + unsigned int count; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + struct elf_segment_map *m; + asection *last_hdr; + unsigned int phdr_index; + bfd_vma maxpagesize; + asection **hdrpp; + + if (elf_tdata (abfd)->segment_map != NULL) + return true; + + if (bfd_count_sections (abfd) == 0) + return true; + + /* Select the allocated sections, and sort them. */ + + sections = (asection **) malloc (bfd_count_sections (abfd) + * sizeof (asection *)); + if (sections == NULL) { - unsigned int al; + bfd_set_error (bfd_error_no_memory); + goto error_return; + } - al = i_shdrp->sh_addralign; - if (al > 1) - offset = BFD_ALIGN (offset, al); + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_ALLOC) != 0) + { + sections[i] = s; + ++i; + } } - i_shdrp->sh_offset = offset; - if (i_shdrp->bfd_section != NULL) - i_shdrp->bfd_section->filepos = offset; - if (i_shdrp->sh_type != SHT_NOBITS) - offset += i_shdrp->sh_size; - return offset; -} + BFD_ASSERT (i <= bfd_count_sections (abfd)); + count = i; -/* Get the size of the program header. + qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); - SORTED_HDRS, if non-NULL, is an array of COUNT pointers to headers sorted - by VMA. Non-allocated sections (!SHF_ALLOC) must appear last. All - section VMAs and sizes are known so we can compute the correct value. - (??? This may not be perfectly true. What cases do we miss?) + /* Build the mapping. */ - If SORTED_HDRS is NULL we assume there are two segments: text and data - (exclusive of .interp and .dynamic). + mfirst = NULL; + pm = &mfirst; - If this is called by the linker before any of the section VMA's are set, it - can't calculate the correct value for a strange memory layout. This only - happens when SIZEOF_HEADERS is used in a linker script. In this case, - SORTED_HDRS is NULL and we assume the normal scenario of one text and one - data segment (exclusive of .interp and .dynamic). + /* If we have a .interp section, then create a PT_PHDR segment for + the program headers and a PT_INTERP segment for the .interp + section. */ + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) + { + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + m->next = NULL; + m->p_type = PT_PHDR; + /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ + m->p_flags = PF_R | PF_X; + m->p_flags_valid = 1; - ??? User written scripts must either not use SIZEOF_HEADERS, or assume there - will be two segments. */ + *pm = m; + pm = &m->next; -static bfd_size_type -get_program_header_size (abfd, sorted_hdrs, count, maxpagesize) - bfd *abfd; - Elf_Internal_Shdr **sorted_hdrs; - unsigned int count; - bfd_vma maxpagesize; -{ - size_t segs; - asection *s; - struct elf_backend_data *bed = get_elf_backend_data (abfd); + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + m->next = NULL; + m->p_type = PT_INTERP; + m->count = 1; + m->sections[0] = s; - /* We can't return a different result each time we're called. */ - if (elf_tdata (abfd)->program_header_size != 0) - return elf_tdata (abfd)->program_header_size; + *pm = m; + pm = &m->next; + } - if (sorted_hdrs != NULL) + /* Look through the sections. We put sections in the same program + segment when the start of the second section can be placed within + a few bytes of the end of the first section. */ + last_hdr = NULL; + phdr_index = 0; + maxpagesize = get_elf_backend_data (abfd)->maxpagesize; + for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) { - unsigned int i; - unsigned int last_type; - Elf_Internal_Shdr **hdrpp; - /* What we think the current segment's offset is. */ - bfd_vma p_offset; - /* What we think the current segment's address is. */ - bfd_vma p_vaddr; - /* How big we think the current segment is. */ - bfd_vma p_memsz; - /* What we think the current file offset is. */ - bfd_vma file_offset; - bfd_vma next_offset; - - /* Scan the headers and compute the number of segments required. This - code is intentionally similar to the code in map_program_segments. - - The `sh_offset' field isn't valid at this point, so we keep our own - running total in `file_offset'. - - This works because section VMAs are already known. */ - - segs = 1; - /* Make sure the first section goes in the first segment. */ - file_offset = p_offset = sorted_hdrs[0]->sh_addr % maxpagesize; - p_vaddr = sorted_hdrs[0]->sh_addr; - p_memsz = 0; - last_type = SHT_PROGBITS; - - for (i = 0, hdrpp = sorted_hdrs; i < count; i++, hdrpp++) - { - Elf_Internal_Shdr *hdr; + asection *hdr; - hdr = *hdrpp; + hdr = *hdrpp; - /* Ignore any section which will not be part of the process - image. */ - if ((hdr->sh_flags & SHF_ALLOC) == 0) - continue; - - /* Keep track of where this and the next sections go. - The section VMA must equal the file position modulo - the page size. */ - file_offset += (hdr->sh_addr - file_offset) % maxpagesize; - next_offset = file_offset; - if (hdr->sh_type != SHT_NOBITS) - next_offset = file_offset + hdr->sh_size; - - /* If this section fits in the segment we are constructing, add - it in. */ - if ((file_offset - (p_offset + p_memsz) - == hdr->sh_addr - (p_vaddr + p_memsz)) - && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS)) - { - bfd_size_type adjust; + /* See if this section and the last one will fit in the same + segment. */ + if (last_hdr == NULL + || ((BFD_ALIGN (last_hdr->lma + last_hdr->_raw_size, maxpagesize) + >= hdr->lma) + && ((last_hdr->flags & SEC_LOAD) != 0 + || (hdr->flags & SEC_LOAD) == 0))) + { + last_hdr = hdr; + continue; + } - adjust = hdr->sh_addr - (p_vaddr + p_memsz); - p_memsz += hdr->sh_size + adjust; - file_offset = next_offset; - last_type = hdr->sh_type; - continue; - } + /* This section won't fit in the program segment. We must + create a new program header holding all the sections from + phdr_index until hdr. */ - /* The section won't fit, start a new segment. */ - ++segs; + m = make_mapping (abfd, sections, phdr_index, i); + if (m == NULL) + goto error_return; - /* Initialize the segment. */ - p_vaddr = hdr->sh_addr; - p_memsz = hdr->sh_size; - p_offset = file_offset; - file_offset = next_offset; + *pm = m; + pm = &m->next; - last_type = hdr->sh_type; - } + last_hdr = hdr; + phdr_index = i; } - else + + /* Create a final PT_LOAD program segment. */ + if (last_hdr != NULL) { - /* Assume we will need exactly two PT_LOAD segments: one for text - and one for data. */ - segs = 2; + m = make_mapping (abfd, sections, phdr_index, i); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; } - s = bfd_get_section_by_name (abfd, ".interp"); + /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ + s = bfd_get_section_by_name (abfd, ".dynamic"); if (s != NULL && (s->flags & SEC_LOAD) != 0) { - /* If we have a loadable interpreter section, we need a - PT_INTERP segment. In this case, assume we also need a - PT_PHDR segment, although that may not be true for all - targets. */ - segs += 2; - } + m = ((struct elf_segment_map *) + bfd_zalloc (abfd, sizeof (struct elf_segment_map))); + if (m == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + m->next = NULL; + m->p_type = PT_DYNAMIC; + m->count = 1; + m->sections[0] = s; - if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) - { - /* We need a PT_DYNAMIC segment. */ - ++segs; + *pm = m; + pm = &m->next; } - /* Let the backend count up any program headers it might need. */ - if (bed->elf_backend_create_program_headers) - segs = ((*bed->elf_backend_create_program_headers) - (abfd, (Elf_Internal_Phdr *) NULL, segs)); + free (sections); + sections = NULL; - elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; - return elf_tdata (abfd)->program_header_size; + elf_tdata (abfd)->segment_map = mfirst; + return true; + + error_return: + if (sections != NULL) + free (sections); + return false; } -/* Create the program header. OFF is the file offset where the - program header should be written. FIRST is the first loadable ELF - section. SORTED_HDRS is the ELF sections sorted by section - address. PHDR_SIZE is the size of the program header as returned - by get_program_header_size. */ +/* Sort sections by VMA. */ -static file_ptr -map_program_segments (abfd, off, first, sorted_hdrs, phdr_size) - bfd *abfd; - file_ptr off; - Elf_Internal_Shdr *first; - Elf_Internal_Shdr **sorted_hdrs; - bfd_size_type phdr_size; +static int +elf_sort_sections (arg1, arg2) + const PTR arg1; + const PTR arg2; { - Elf_Internal_Phdr phdrs[10]; - unsigned int phdr_count; - Elf_Internal_Phdr *phdr; - int phdr_size_adjust; - unsigned int i; - Elf_Internal_Shdr **hdrpp; - asection *sinterp, *sdyn; - unsigned int last_type; - Elf_Internal_Ehdr *i_ehdrp; - struct elf_backend_data *bed = get_elf_backend_data (abfd); + const asection *sec1 = *(const asection **) arg1; + const asection *sec2 = *(const asection **) arg2; - BFD_ASSERT ((abfd->flags & (EXEC_P | DYNAMIC)) != 0); - BFD_ASSERT (phdr_size / sizeof (Elf_Internal_Phdr) - <= sizeof phdrs / sizeof (phdrs[0])); + if (sec1->vma < sec2->vma) + return -1; + else if (sec1->vma > sec2->vma) + return 1; - phdr_count = 0; - phdr = phdrs; + /* Put !SEC_LOAD sections after SEC_LOAD ones. */ - if (bed->want_hdr_in_seg) - phdr_size_adjust = first->sh_offset - phdr_size; - else - phdr_size_adjust = 0; +#define TOEND(x) (((x)->flags & SEC_LOAD) == 0) - /* If we have a loadable .interp section, we must create a PT_INTERP - segment which must precede all PT_LOAD segments. We assume that - we must also create a PT_PHDR segment, although that may not be - true for all targets. */ - sinterp = bfd_get_section_by_name (abfd, ".interp"); - if (sinterp != NULL && (sinterp->flags & SEC_LOAD) != 0) - { - BFD_ASSERT (first != NULL); + if (TOEND (sec1)) + if (TOEND (sec2)) + return sec1->target_index - sec2->target_index; + else + return 1; - phdr->p_type = PT_PHDR; + if (TOEND (sec2)) + return -1; - phdr->p_offset = off; +#undef TOEND - /* Account for any adjustment made because of the alignment of - the first loadable section. */ - phdr_size_adjust = (first->sh_offset - phdr_size) - off; - BFD_ASSERT (phdr_size_adjust >= 0 && phdr_size_adjust < 128); + /* Sort by size, to put zero sized sections before others at the + same address. */ - /* The program header precedes all loadable sections. This lets - us compute its loadable address. This depends on the linker - script. */ - phdr->p_vaddr = first->sh_addr - (phdr_size + phdr_size_adjust); + if (sec1->_raw_size < sec2->_raw_size) + return -1; + if (sec1->_raw_size > sec2->_raw_size) + return 1; - phdr->p_paddr = 0; - phdr->p_filesz = phdr_size; - phdr->p_memsz = phdr_size; + return sec1->target_index - sec2->target_index; +} - /* FIXME: UnixWare and Solaris set PF_X, Irix 5 does not. */ - phdr->p_flags = PF_R | PF_X; +/* Assign file positions to the sections based on the mapping from + sections to segments. This function also sets up some fields in + the file header, and writes out the program headers. */ - phdr->p_align = bed->s->file_align; - BFD_ASSERT ((phdr->p_vaddr - phdr->p_offset) % bed->s->file_align == 0); +static boolean +assign_file_positions_for_segments (abfd) + bfd *abfd; +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + unsigned int count; + struct elf_segment_map *m; + unsigned int alloc; + Elf_Internal_Phdr *phdrs; + file_ptr off; + boolean found_load; + Elf_Internal_Phdr *p; + + if (elf_tdata (abfd)->segment_map == NULL) + { + if (! map_sections_to_segments (abfd)) + return false; + } - /* Include the ELF header in the first loadable segment. */ - phdr_size_adjust += off; + count = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++count; - ++phdr_count; - ++phdr; + elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; + elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; + elf_elfheader (abfd)->e_phnum = count; - phdr->p_type = PT_INTERP; - phdr->p_offset = sinterp->filepos; - phdr->p_vaddr = sinterp->vma; - phdr->p_paddr = 0; - phdr->p_filesz = sinterp->_raw_size; - phdr->p_memsz = sinterp->_raw_size; - phdr->p_flags = PF_R; - phdr->p_align = 1 << bfd_get_section_alignment (abfd, sinterp); + if (count == 0) + return true; - ++phdr_count; - ++phdr; + /* Let the backend count up any program headers it might need. */ + if (bed->elf_backend_create_program_headers) + count = ((*bed->elf_backend_create_program_headers) + (abfd, (Elf_Internal_Phdr *) NULL, count)); + + /* If we already counted the number of program segments, make sure + that we allocated enough space. This happens when SIZEOF_HEADERS + is used in a linker script. */ + alloc = elf_tdata (abfd)->program_header_size / bed->s->sizeof_phdr; + if (alloc != 0 && count > alloc) + { + ((*_bfd_error_handler) + ("%s: Not enough room for program headers (allocated %u, need %u)", + bfd_get_filename (abfd), alloc, count)); + bfd_set_error (bfd_error_bad_value); + return false; } - /* Look through the sections to see how they will be divided into - program segments. The sections must be arranged in order by - sh_addr for this to work correctly. */ - phdr->p_type = PT_NULL; - last_type = SHT_PROGBITS; - for (i = 1, hdrpp = sorted_hdrs; - i < elf_elfheader (abfd)->e_shnum; - i++, hdrpp++) + if (alloc == 0) + alloc = count; + + phdrs = ((Elf_Internal_Phdr *) + bfd_alloc (abfd, alloc * sizeof (Elf_Internal_Phdr))); + if (phdrs == NULL) { - Elf_Internal_Shdr *hdr; + bfd_set_error (bfd_error_no_memory); + return false; + } - hdr = *hdrpp; + off = bed->s->sizeof_ehdr; + off += alloc * bed->s->sizeof_phdr; - /* Ignore any section which will not be part of the process - image. */ - if ((hdr->sh_flags & SHF_ALLOC) == 0) - continue; + found_load = false; + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + unsigned int i; + asection **secpp; + boolean adjusted; + + p->p_type = m->p_type; + + if (m->p_flags_valid) + p->p_flags = m->p_flags; + + if (m->count == 0) + p->p_vaddr = 0; + else + p->p_vaddr = m->sections[0]->vma; - /* If this section fits in the segment we are constructing, add - it in. */ - if (phdr->p_type != PT_NULL - && (hdr->sh_offset - (phdr->p_offset + phdr->p_memsz) - == hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz)) - && (last_type != SHT_NOBITS || hdr->sh_type == SHT_NOBITS)) + if (m->p_paddr_valid) + p->p_paddr = m->p_paddr; + else if (m->count == 0) + p->p_paddr = 0; + else + p->p_paddr = m->sections[0]->lma; + + if (p->p_type == PT_LOAD) + p->p_align = bed->maxpagesize; + else if (m->count == 0) + p->p_align = bed->s->file_align; + else + p->p_align = 0; + + p->p_filesz = 0; + p->p_memsz = 0; + + adjusted = false; + if (p->p_type == PT_LOAD) { - bfd_size_type adjust; - - adjust = hdr->sh_addr - (phdr->p_vaddr + phdr->p_memsz); - phdr->p_memsz += hdr->sh_size + adjust; - if (hdr->sh_type != SHT_NOBITS) - phdr->p_filesz += hdr->sh_size + adjust; - if ((hdr->sh_flags & SHF_WRITE) != 0) - phdr->p_flags |= PF_W; - if ((hdr->sh_flags & SHF_EXECINSTR) != 0) - phdr->p_flags |= PF_X; - last_type = hdr->sh_type; - continue; + p->p_offset = off; + + if (! found_load) + { + struct elf_segment_map *mi; + Elf_Internal_Phdr *pi; + Elf_Internal_Phdr *pi_phdr; + + /* This is the first PT_LOAD segment. If there is a + PT_INTERP segment, adjust the offset of this segment + to include the program headers and the file header. */ + pi_phdr = NULL; + for (mi = elf_tdata (abfd)->segment_map, pi = phdrs; + mi != NULL; + mi = mi->next, pi++) + { + if (mi->p_type == PT_INTERP) + { + p->p_offset = 0; + p->p_filesz = off; + p->p_memsz = off; + p->p_vaddr -= off; + p->p_paddr -= off; + adjusted = true; + } + if (mi->p_type == PT_PHDR) + pi_phdr = pi; + } + + /* Set up the PT_PHDR addresses. */ + if (pi_phdr != NULL) + { + pi_phdr->p_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; + pi_phdr->p_paddr = p->p_paddr + bed->s->sizeof_ehdr; + } + + found_load = true; + } } - /* The section won't fit, start a new segment. If we're already in one, - move to the next one. */ - if (phdr->p_type != PT_NULL) + if (! m->p_flags_valid) + p->p_flags = PF_R; + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { - ++phdr; - ++phdr_count; + asection *sec; + flagword flags; + bfd_size_type align; + + sec = *secpp; + flags = sec->flags; + + if (p->p_type == PT_LOAD) + { + bfd_vma adjust; + + /* The section VMA must equal the file position modulo + the page size. */ + adjust = (sec->vma - off) % bed->maxpagesize; + if (adjust != 0) + { + if (i == 0 && ! adjusted) + p->p_offset += adjust; + else + { + p->p_memsz += adjust; + if ((flags & SEC_LOAD) != 0) + p->p_filesz += adjust; + } + off += adjust; + } + + sec->filepos = off; + + if ((flags & SEC_LOAD) != 0) + off += sec->_raw_size; + } + + p->p_memsz += sec->_raw_size; + + if ((flags & SEC_LOAD) != 0) + p->p_filesz += sec->_raw_size; + + align = 1 << bfd_get_section_alignment (abfd, sec); + if (align > p->p_align) + p->p_align = align; + + if (! m->p_flags_valid) + { + if ((flags & SEC_CODE) != 0) + p->p_flags |= PF_X; + if ((flags & SEC_READONLY) == 0) + p->p_flags |= PF_W; + } } + } - /* Initialize the segment. */ - phdr->p_type = PT_LOAD; - phdr->p_offset = hdr->sh_offset; - phdr->p_vaddr = hdr->sh_addr; - phdr->p_paddr = 0; - if (hdr->sh_type == SHT_NOBITS) - phdr->p_filesz = 0; - else - phdr->p_filesz = hdr->sh_size; - phdr->p_memsz = hdr->sh_size; - phdr->p_flags = PF_R; - if ((hdr->sh_flags & SHF_WRITE) != 0) - phdr->p_flags |= PF_W; - if ((hdr->sh_flags & SHF_EXECINSTR) != 0) - phdr->p_flags |= PF_X; - phdr->p_align = bed->maxpagesize; - - if (hdr == first - && (bed->want_hdr_in_seg - || (sinterp != NULL - && (sinterp->flags & SEC_LOAD) != 0))) + /* Now that we have set the section file positions, we can set up + the file positions for the non PT_LOAD segments. */ + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + if (p->p_type != PT_LOAD && m->count > 0) + p->p_offset = m->sections[0]->filepos; + if (p->p_type == PT_PHDR) { - phdr->p_offset -= phdr_size + phdr_size_adjust; - phdr->p_vaddr -= phdr_size + phdr_size_adjust; - phdr->p_filesz += phdr_size + phdr_size_adjust; - phdr->p_memsz += phdr_size + phdr_size_adjust; + p->p_offset = bed->s->sizeof_ehdr; + p->p_filesz = count * bed->s->sizeof_phdr; + p->p_memsz = p->p_filesz; } - - last_type = hdr->sh_type; } - if (phdr->p_type != PT_NULL) + /* Let the backend set up any program headers it might need. */ + if (bed->elf_backend_create_program_headers) + count = ((*bed->elf_backend_create_program_headers) + (abfd, phdrs, count)); + + /* Clear out any program headers we allocated but did not use. */ + for (; count < alloc; count++, p++) { - ++phdr; - ++phdr_count; + memset (p, 0, sizeof *p); + p->p_type = PT_NULL; } - /* If we have a .dynamic section, create a PT_DYNAMIC segment. */ - sdyn = bfd_get_section_by_name (abfd, ".dynamic"); - if (sdyn != NULL && (sdyn->flags & SEC_LOAD) != 0) - { - phdr->p_type = PT_DYNAMIC; - phdr->p_offset = sdyn->filepos; - phdr->p_vaddr = sdyn->vma; - phdr->p_paddr = 0; - phdr->p_filesz = sdyn->_raw_size; - phdr->p_memsz = sdyn->_raw_size; - phdr->p_flags = PF_R; - if ((sdyn->flags & SEC_READONLY) == 0) - phdr->p_flags |= PF_W; - if ((sdyn->flags & SEC_CODE) != 0) - phdr->p_flags |= PF_X; - phdr->p_align = 1 << bfd_get_section_alignment (abfd, sdyn); + elf_tdata (abfd)->phdr = phdrs; - ++phdr; - ++phdr_count; - } + elf_tdata (abfd)->next_file_pos = off; - /* Let the backend create additional program headers. */ - if (bed->elf_backend_create_program_headers) - phdr_count = (*bed->elf_backend_create_program_headers) (abfd, - phdrs, - phdr_count); + /* Write out the program headers. */ + if (bfd_seek (abfd, bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, phdrs, alloc) != 0) + return false; + + return true; +} + +/* Get the size of the program header. + + If this is called by the linker before any of the section VMA's are set, it + can't calculate the correct value for a strange memory layout. This only + happens when SIZEOF_HEADERS is used in a linker script. In this case, + SORTED_HDRS is NULL and we assume the normal scenario of one text and one + data segment (exclusive of .interp and .dynamic). + + ??? User written scripts must either not use SIZEOF_HEADERS, or assume there + will be two segments. */ + +static bfd_size_type +get_program_header_size (abfd) + bfd *abfd; +{ + size_t segs; + asection *s; + struct elf_backend_data *bed = get_elf_backend_data (abfd); + + /* We can't return a different result each time we're called. */ + if (elf_tdata (abfd)->program_header_size != 0) + return elf_tdata (abfd)->program_header_size; - /* Make sure the return value from get_program_header_size matches - what we computed here. Actually, it's OK if we allocated too - much space in the program header. */ - if (phdr_count > phdr_size / bed->s->sizeof_phdr) + /* Assume we will need exactly two PT_LOAD segments: one for text + and one for data. */ + segs = 2; + + s = bfd_get_section_by_name (abfd, ".interp"); + if (s != NULL && (s->flags & SEC_LOAD) != 0) { - ((*_bfd_error_handler) - ("%s: Not enough room for program headers (allocated %lu, need %u)", - bfd_get_filename (abfd), - (unsigned long) (phdr_size / bed->s->sizeof_phdr), - phdr_count)); - bfd_set_error (bfd_error_bad_value); - return (file_ptr) -1; + /* If we have a loadable interpreter section, we need a + PT_INTERP segment. In this case, assume we also need a + PT_PHDR segment, although that may not be true for all + targets. */ + segs += 2; } - /* Set up program header information. */ - i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_phentsize = bed->s->sizeof_phdr; - i_ehdrp->e_phoff = off; - i_ehdrp->e_phnum = phdr_count; - - /* Save the program headers away. I don't think anybody uses this - information right now. */ - elf_tdata (abfd)->phdr = ((Elf_Internal_Phdr *) - bfd_alloc (abfd, - (phdr_count - * sizeof (Elf_Internal_Phdr)))); - if (elf_tdata (abfd)->phdr == NULL && phdr_count != 0) + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) { - bfd_set_error (bfd_error_no_memory); - return (file_ptr) -1; + /* We need a PT_DYNAMIC segment. */ + ++segs; } - memcpy (elf_tdata (abfd)->phdr, phdrs, - phdr_count * sizeof (Elf_Internal_Phdr)); - /* Write out the program headers. */ - if (bfd_seek (abfd, off, SEEK_SET) != 0) - return (file_ptr) -1; - - if (bed->s->write_out_phdrs (abfd, phdrs, phdr_count) != 0) - return (file_ptr) -1; + /* Let the backend count up any program headers it might need. */ + if (bed->elf_backend_create_program_headers) + segs = ((*bed->elf_backend_create_program_headers) + (abfd, (Elf_Internal_Phdr *) NULL, segs)); - return off + phdr_count * bed->s->sizeof_phdr; + elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; + return elf_tdata (abfd)->program_header_size; } /* Work out the file positions of all the sections. This is called by @@ -1837,15 +2009,11 @@ map_program_segments (abfd, off, first, sorted_hdrs, phdr_size) positions in assign_file_positions_for_relocs, which is called by write_object_contents and final_link. - If DOSYMS is false, we do not assign file positions for the symbol - table or the string table. */ - -static int elf_sort_hdrs PARAMS ((const PTR, const PTR)); + We also don't set the positions of the .symtab and .strtab here. */ static boolean -assign_file_positions_except_relocs (abfd, dosyms) +assign_file_positions_except_relocs (abfd) bfd *abfd; - boolean dosyms; { struct elf_obj_tdata * const tdata = elf_tdata (abfd); Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd); @@ -1853,14 +2021,14 @@ assign_file_positions_except_relocs (abfd, dosyms) file_ptr off; struct elf_backend_data *bed = get_elf_backend_data (abfd); - /* Start after the ELF header. */ - off = i_ehdrp->e_ehsize; - if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) { Elf_Internal_Shdr **hdrpp; unsigned int i; + /* Start after the ELF header. */ + off = i_ehdrp->e_ehsize; + /* We are not creating an executable, which means that we are not creating a program header, and that the actual order of the sections in the file is unimportant. */ @@ -1874,9 +2042,8 @@ assign_file_positions_except_relocs (abfd, dosyms) hdr->sh_offset = -1; continue; } - if (! dosyms - && (i == tdata->symtab_section - || i == tdata->strtab_section)) + if (i == tdata->symtab_section + || i == tdata->strtab_section) { hdr->sh_offset = -1; continue; @@ -1887,97 +2054,45 @@ assign_file_positions_except_relocs (abfd, dosyms) } else { - file_ptr phdr_off; - bfd_size_type phdr_size; - bfd_vma maxpagesize; - size_t hdrppsize; - Elf_Internal_Shdr **sorted_hdrs; - Elf_Internal_Shdr **hdrpp; unsigned int i; - Elf_Internal_Shdr *first; - file_ptr phdr_map; - - /* We are creating an executable. */ - - maxpagesize = get_elf_backend_data (abfd)->maxpagesize; - if (maxpagesize == 0) - maxpagesize = 1; - - /* We must sort the sections. The GNU linker will always create - the sections in an appropriate order, but the Irix 5 linker - will not. We don't include the dummy first section in the - sort. We sort sections which are not SHF_ALLOC to the end. */ - hdrppsize = (i_ehdrp->e_shnum - 1) * sizeof (Elf_Internal_Shdr *); - sorted_hdrs = (Elf_Internal_Shdr **) malloc (hdrppsize); - if (sorted_hdrs == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + Elf_Internal_Shdr **hdrpp; - memcpy (sorted_hdrs, i_shdrpp + 1, hdrppsize); - qsort (sorted_hdrs, (size_t) i_ehdrp->e_shnum - 1, - sizeof (Elf_Internal_Shdr *), elf_sort_hdrs); - - /* We can't actually create the program header until we have set the - file positions for the sections, and we can't do that until we know - how big the header is going to be. */ - off = align_file_position (off, bed->s->file_align); - phdr_size = get_program_header_size (abfd, - sorted_hdrs, i_ehdrp->e_shnum - 1, - maxpagesize); - if (phdr_size == (bfd_size_type) -1) + /* Assign file positions for the loaded sections based on the + assignment of sections to segments. */ + if (! assign_file_positions_for_segments (abfd)) return false; - /* Compute the file offsets of each section. */ - phdr_off = off; - off += phdr_size; - first = NULL; - for (i = 1, hdrpp = sorted_hdrs; i < i_ehdrp->e_shnum; i++, hdrpp++) + /* Assign file positions for the other sections. */ + + off = elf_tdata (abfd)->next_file_pos; + for (i = 1, hdrpp = i_shdrpp + 1; i < i_ehdrp->e_shnum; i++, hdrpp++) { Elf_Internal_Shdr *hdr; hdr = *hdrpp; - if ((hdr->sh_flags & SHF_ALLOC) == 0) - { - if (hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) - { - hdr->sh_offset = -1; - continue; - } - if (! dosyms - && (hdr == i_shdrpp[tdata->symtab_section] - || hdr == i_shdrpp[tdata->strtab_section])) - { - hdr->sh_offset = -1; - continue; - } - off = _bfd_elf_assign_file_position_for_section (hdr, off, - true); - } - else + if (hdr->bfd_section != NULL + && hdr->bfd_section->filepos != 0) + hdr->sh_offset = hdr->bfd_section->filepos; + else if ((hdr->sh_flags & SHF_ALLOC) != 0) { - if (first == NULL) - first = hdr; - - /* The section VMA must equal the file position modulo - the page size. This is required by the program - header. */ - off += (hdr->sh_addr - off) % maxpagesize; + ((*_bfd_error_handler) + ("%s: warning: allocated section `%s' not in segment", + bfd_get_filename (abfd), + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + off += (hdr->sh_addr - off) % bed->maxpagesize; off = _bfd_elf_assign_file_position_for_section (hdr, off, false); } - } - - /* Create the program header. */ - phdr_map = map_program_segments (abfd, phdr_off, first, sorted_hdrs, - phdr_size); - if (phdr_map == (file_ptr) -1) - return false; - BFD_ASSERT ((bfd_size_type) phdr_map - <= (bfd_size_type) phdr_off + phdr_size); - - free (sorted_hdrs); + else if (hdr->sh_type == SHT_REL + || hdr->sh_type == SHT_RELA + || hdr == i_shdrpp[tdata->symtab_section] + || hdr == i_shdrpp[tdata->strtab_section]) + hdr->sh_offset = -1; + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, true); + } } /* Place the section headers. */ @@ -1990,47 +2105,6 @@ assign_file_positions_except_relocs (abfd, dosyms) return true; } -/* Sort the ELF headers by VMA. We sort headers which are not - SHF_ALLOC to the end. */ -static int -elf_sort_hdrs (arg1, arg2) - const PTR arg1; - const PTR arg2; -{ - int ret; - const Elf_Internal_Shdr *hdr1 = *(const Elf_Internal_Shdr **) arg1; - const Elf_Internal_Shdr *hdr2 = *(const Elf_Internal_Shdr **) arg2; - -#define TOEND(x) (((x)->sh_flags & SHF_ALLOC)==0) - - if (TOEND (hdr1)) - if (TOEND (hdr2)) - return 0; - else - return 1; - - if (TOEND (hdr2)) - return -1; - - if (hdr1->sh_addr < hdr2->sh_addr) - return -1; - else if (hdr1->sh_addr > hdr2->sh_addr) - return 1; - - /* Put !SHT_NOBITS sections before SHT_NOBITS ones. - The main loop in map_program_segments requires this. */ - - ret = (hdr1->sh_type == SHT_NOBITS) - (hdr2->sh_type == SHT_NOBITS); - - if (ret != 0) - return ret; - if (hdr1->sh_size < hdr2->sh_size) - return -1; - if (hdr1->sh_size > hdr2->sh_size) - return 1; - return 0; -} - static boolean prep_headers (abfd) bfd *abfd; @@ -2325,6 +2399,80 @@ _bfd_elf_symbol_from_bfd_symbol (abfd, asym_ptr_ptr) return idx; } +/* Copy private section information. This copies over the entsize + field, and sometimes the info field. */ + +boolean +_bfd_elf_copy_private_section_data (ibfd, isec, obfd, osec) + bfd *ibfd; + asection *isec; + bfd *obfd; + asection *osec; +{ + Elf_Internal_Shdr *ihdr, *ohdr; + + if (ibfd->xvec->flavour != bfd_target_elf_flavour + || obfd->xvec->flavour != bfd_target_elf_flavour) + return true; + + ihdr = &elf_section_data (isec)->this_hdr; + ohdr = &elf_section_data (osec)->this_hdr; + + ohdr->sh_entsize = ihdr->sh_entsize; + + if (ihdr->sh_type == SHT_SYMTAB + || ihdr->sh_type == SHT_DYNSYM) + ohdr->sh_info = ihdr->sh_info; + + return true; +} + +/* Copy private symbol information. If this symbol is in a section + which we did not map into a BFD section, try to map the section + index correctly. We use special macro definitions for the mapped + section indices; these definitions are interpreted by the + swap_out_syms function. */ + +#define MAP_ONESYMTAB (SHN_LORESERVE - 1) +#define MAP_DYNSYMTAB (SHN_LORESERVE - 2) +#define MAP_STRTAB (SHN_LORESERVE - 3) +#define MAP_SHSTRTAB (SHN_LORESERVE - 4) + +boolean +_bfd_elf_copy_private_symbol_data (ibfd, isymarg, obfd, osymarg) + bfd *ibfd; + asymbol *isymarg; + bfd *obfd; + asymbol *osymarg; +{ + elf_symbol_type *isym, *osym; + + isym = elf_symbol_from (ibfd, isymarg); + osym = elf_symbol_from (obfd, osymarg); + + if (isym != NULL + && osym != NULL + && bfd_is_abs_section (isym->symbol.section)) + { + unsigned int shndx; + + shndx = isym->internal_elf_sym.st_shndx; + if (shndx == elf_onesymtab (ibfd)) + shndx = MAP_ONESYMTAB; + else if (shndx == elf_dynsymtab (ibfd)) + shndx = MAP_DYNSYMTAB; + else if (shndx == elf_tdata (ibfd)->strtab_section) + shndx = MAP_STRTAB; + else if (shndx == elf_tdata (ibfd)->shstrtab_section) + shndx = MAP_SHSTRTAB; + osym->internal_elf_sym.st_shndx = shndx; + } + + return true; +} + +/* Swap out the symbols. */ + static boolean swap_out_syms (abfd, sttp) bfd *abfd; @@ -2429,21 +2577,56 @@ swap_out_syms (abfd, sttp) value += sec->vma; sym.st_value = value; sym.st_size = type_ptr ? type_ptr->internal_elf_sym.st_size : 0; - sym.st_shndx = shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - if (shndx == -1) + + if (bfd_is_abs_section (sec) + && type_ptr != NULL + && type_ptr->internal_elf_sym.st_shndx != 0) { - asection *sec2; - /* Writing this would be a hell of a lot easier if we had - some decent documentation on bfd, and knew what to expect - of the library, and what to demand of applications. For - example, it appears that `objcopy' might not set the - section of a symbol to be a section that is actually in - the output file. */ - sec2 = bfd_get_section_by_name (abfd, sec->name); - BFD_ASSERT (sec2 != 0); - sym.st_shndx = shndx = _bfd_elf_section_from_bfd_section (abfd, sec2); - BFD_ASSERT (shndx != -1); + /* This symbol is in a real ELF section which we did + not create as a BFD section. Undo the mapping done + by copy_private_symbol_data. */ + shndx = type_ptr->internal_elf_sym.st_shndx; + switch (shndx) + { + case MAP_ONESYMTAB: + shndx = elf_onesymtab (abfd); + break; + case MAP_DYNSYMTAB: + shndx = elf_dynsymtab (abfd); + break; + case MAP_STRTAB: + shndx = elf_tdata (abfd)->strtab_section; + break; + case MAP_SHSTRTAB: + shndx = elf_tdata (abfd)->shstrtab_section; + break; + default: + break; + } + } + else + { + shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + + if (shndx == -1) + { + asection *sec2; + + /* Writing this would be a hell of a lot easier if + we had some decent documentation on bfd, and + knew what to expect of the library, and what to + demand of applications. For example, it + appears that `objcopy' might not set the + section of a symbol to be a section that is + actually in the output file. */ + sec2 = bfd_get_section_by_name (abfd, sec->name); + BFD_ASSERT (sec2 != 0); + shndx = _bfd_elf_section_from_bfd_section (abfd, sec2); + BFD_ASSERT (shndx != -1); + } } + + sym.st_shndx = shndx; } if (bfd_is_com_section (syms[idx]->section)) @@ -2713,8 +2896,7 @@ _bfd_elf_sizeof_headers (abfd, reloc) ret = get_elf_backend_data (abfd)->s->sizeof_ehdr; if (! reloc) - ret += get_program_header_size (abfd, (Elf_Internal_Shdr **) NULL, 0, - (bfd_vma) 0); + ret += get_program_header_size (abfd); return ret; }