diff options
author | dim <dim@FreeBSD.org> | 2010-11-01 19:35:33 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2010-11-01 19:35:33 +0000 |
commit | 3f5c947f4453c6016a2a6a9636367ee3f48fc6fc (patch) | |
tree | 461aafc934d462eb9b9221308f8e25238c0ada62 /contrib/binutils/bfd/elf.c | |
parent | e6be3e7867eb43d220575baee2ce5662fb03e46c (diff) | |
parent | d0f678fa0ff3f08a4eca29daf4d1ac39797b6326 (diff) | |
download | FreeBSD-src-3f5c947f4453c6016a2a6a9636367ee3f48fc6fc.zip FreeBSD-src-3f5c947f4453c6016a2a6a9636367ee3f48fc6fc.tar.gz |
Merge ^/vendor/binutils/dist@214571 into contrib/binutils, which brings
us up to version 2.17.50.20070703, at the last GPLv2 commit.
Amongst others, this added upstream support for some FreeBSD-specific
things that we previously had to manually hack in, such as the OSABI
label support, and so on.
There are also quite a number of new files, some for cpu's (e.g. SPU)
that we may or may not be interested in, but those can be cleaned up
later on, if needed.
Diffstat (limited to 'contrib/binutils/bfd/elf.c')
-rw-r--r-- | contrib/binutils/bfd/elf.c | 2792 |
1 files changed, 1624 insertions, 1168 deletions
diff --git a/contrib/binutils/bfd/elf.c b/contrib/binutils/bfd/elf.c index c2ee684..e819609 100644 --- a/contrib/binutils/bfd/elf.c +++ b/contrib/binutils/bfd/elf.c @@ -1,7 +1,7 @@ /* ELF executable support for BFD. Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, - 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -37,8 +37,8 @@ SECTION /* For sparc64-cross-sparc32. */ #define _SYSCALL32 -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "libbfd.h" #define ARCH_SIZE 0 @@ -210,16 +210,32 @@ bfd_elf_hash (const char *namearg) return h & 0xffffffff; } +/* DT_GNU_HASH hash function. Do not change this function; you will + cause invalid hash tables to be generated. */ + +unsigned long +bfd_elf_gnu_hash (const char *namearg) +{ + const unsigned char *name = (const unsigned char *) namearg; + unsigned long h = 5381; + unsigned char ch; + + while ((ch = *name++) != '\0') + h = (h << 5) + h + ch; + return h & 0xffffffff; +} + bfd_boolean bfd_elf_mkobject (bfd *abfd) { - /* This just does initialization. */ - /* coff_mkobject zalloc's space for tdata.coff_obj_data ... */ - elf_tdata (abfd) = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); - if (elf_tdata (abfd) == 0) - return FALSE; - /* Since everything is done at close time, do we need any - initialization? */ + if (abfd->tdata.any == NULL) + { + abfd->tdata.any = bfd_zalloc (abfd, sizeof (struct elf_obj_tdata)); + if (abfd->tdata.any == NULL) + return FALSE; + } + + elf_tdata (abfd)->program_header_size = (bfd_size_type) -1; return TRUE; } @@ -240,7 +256,9 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex) bfd_size_type shstrtabsize; i_shdrp = elf_elfsections (abfd); - if (i_shdrp == 0 || i_shdrp[shindex] == 0) + if (i_shdrp == 0 + || shindex >= elf_numsections (abfd) + || i_shdrp[shindex] == 0) return NULL; shstrtab = i_shdrp[shindex]->contents; @@ -279,6 +297,9 @@ bfd_elf_string_from_elf_section (bfd *abfd, if (strindex == 0) return ""; + if (elf_elfsections (abfd) == NULL || shindex >= elf_numsections (abfd)) + return NULL; + hdr = elf_elfsections (abfd)[shindex]; if (hdr->contents == NULL @@ -388,7 +409,15 @@ bfd_elf_get_elf_syms (bfd *ibfd, for (esym = extsym_buf, isym = intsym_buf, shndx = extshndx_buf; isym < isymend; esym += extsym_size, isym++, shndx = shndx != NULL ? shndx + 1 : NULL) - (*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym); + if (!(*bed->s->swap_symbol_in) (ibfd, esym, shndx, isym)) + { + symoffset += (esym - (bfd_byte *) extsym_buf) / extsym_size; + (*_bfd_error_handler) (_("%B symbol number %lu references " + "nonexistent SHT_SYMTAB_SHNDX section"), + ibfd, (unsigned long) symoffset); + intsym_buf = NULL; + goto out; + } out: if (alloc_ext != NULL) @@ -481,10 +510,18 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) section with just a flag word (ie. sh_size is 4), ignore it. */ shnum = elf_numsections (abfd); num_group = 0; + +#define IS_VALID_GROUP_SECTION_HEADER(shdr) \ + ( (shdr)->sh_type == SHT_GROUP \ + && (shdr)->sh_size >= (2 * GRP_ENTRY_SIZE) \ + && (shdr)->sh_entsize == GRP_ENTRY_SIZE \ + && ((shdr)->sh_size % GRP_ENTRY_SIZE) == 0) + for (i = 0; i < shnum; i++) { Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; - if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8) + + if (IS_VALID_GROUP_SECTION_HEADER (shdr)) num_group += 1; } @@ -509,7 +546,8 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) for (i = 0; i < shnum; i++) { Elf_Internal_Shdr *shdr = elf_elfsections (abfd)[i]; - if (shdr->sh_type == SHT_GROUP && shdr->sh_size >= 8) + + if (IS_VALID_GROUP_SECTION_HEADER (shdr)) { unsigned char *src; Elf_Internal_Group *dest; @@ -523,8 +561,18 @@ setup_group (bfd *abfd, Elf_Internal_Shdr *hdr, asection *newsect) amt = shdr->sh_size * sizeof (*dest) / 4; shdr->contents = bfd_alloc2 (abfd, shdr->sh_size, sizeof (*dest) / 4); - if (shdr->contents == NULL - || bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 + /* PR binutils/4110: Handle corrupt group headers. */ + if (shdr->contents == NULL) + { + _bfd_error_handler + (_("%B: Corrupt size field in group section header: 0x%lx"), abfd, shdr->sh_size); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + memset (shdr->contents, 0, amt); + + if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0 || (bfd_bread (shdr->contents, shdr->sh_size, abfd) != shdr->sh_size)) return FALSE; @@ -804,24 +852,24 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, int len; } debug_sections [] = { - { "debug", 5 }, /* 'd' */ + { STRING_COMMA_LEN ("debug") }, /* 'd' */ { NULL, 0 }, /* 'e' */ { NULL, 0 }, /* 'f' */ - { "gnu.linkonce.wi.", 17 }, /* 'g' */ + { STRING_COMMA_LEN ("gnu.linkonce.wi.") }, /* 'g' */ { NULL, 0 }, /* 'h' */ { NULL, 0 }, /* 'i' */ { NULL, 0 }, /* 'j' */ { NULL, 0 }, /* 'k' */ - { "line", 4 }, /* 'l' */ + { STRING_COMMA_LEN ("line") }, /* 'l' */ { NULL, 0 }, /* 'm' */ { NULL, 0 }, /* 'n' */ { NULL, 0 }, /* 'o' */ { NULL, 0 }, /* 'p' */ { NULL, 0 }, /* 'q' */ { NULL, 0 }, /* 'r' */ - { "stab", 4 } /* 's' */ + { STRING_COMMA_LEN ("stab") } /* 's' */ }; - + if (name [0] == '.') { int i = name [1] - 'd'; @@ -840,7 +888,7 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, The symbols will be defined as weak, so that multiple definitions are permitted. The GNU linker extension is to actually discard all but one of the sections. */ - if (strncmp (name, ".gnu.linkonce", sizeof ".gnu.linkonce" - 1) == 0 + if (CONST_STRNEQ (name, ".gnu.linkonce") && elf_next_in_group (newsect) == NULL) flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_DISCARD; @@ -858,8 +906,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, unsigned int i; /* Look through the phdrs to see if we need to adjust the lma. - If all the p_paddr fields are zero, we ignore them, since - some ELF linkers produce such output. */ + If all the p_paddr fields are zero, we ignore them, since + some ELF linkers produce such output. */ phdr = elf_tdata (abfd)->phdr; for (i = 0; i < elf_elfheader (abfd)->e_phnum; i++, phdr++) { @@ -880,9 +928,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, refuse to set the LMA if it was 0. This is wrong though, as a perfectly valid initialised segment can have a p_paddr of zero. Some architectures, eg ARM, - place special significance on the address 0 and - executables need to be able to have a segment which - covers this address. */ + place special significance on the address 0 and + executables need to be able to have a segment which + covers this address. */ if (phdr->p_type == PT_LOAD && (bfd_vma) hdr->sh_offset >= phdr->p_offset && (hdr->sh_offset + hdr->sh_size @@ -1069,6 +1117,10 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) elf_gp (obfd) = elf_gp (ibfd); elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags; elf_flags_init (obfd) = TRUE; + + /* Copy object attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); + return TRUE; } @@ -1243,6 +1295,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break; case DT_USED: name = "USED"; break; case DT_FILTER: name = "FILTER"; stringp = TRUE; break; + case DT_GNU_HASH: name = "GNU_HASH"; break; } fprintf (f, " %-11s ", name); @@ -1476,9 +1529,9 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) - offsetof (struct elf_link_hash_entry, size))); /* Assume that we have been called by a non-ELF symbol reader. - This flag is then reset by the code which reads an ELF input - file. This ensures that a symbol created by a non-ELF symbol - reader will have the flag set correctly. */ + This flag is then reset by the code which reads an ELF input + file. This ensures that a symbol created by a non-ELF symbol + reader will have the flag set correctly. */ ret->non_elf = 1; } @@ -1571,27 +1624,13 @@ _bfd_elf_link_hash_table_init bfd_boolean ret; int can_refcount = get_elf_backend_data (abfd)->can_refcount; - table->dynamic_sections_created = FALSE; - table->dynobj = NULL; + memset (table, 0, sizeof * table); table->init_got_refcount.refcount = can_refcount - 1; table->init_plt_refcount.refcount = can_refcount - 1; table->init_got_offset.offset = -(bfd_vma) 1; table->init_plt_offset.offset = -(bfd_vma) 1; /* The first dynamic symbol is a dummy. */ table->dynsymcount = 1; - table->dynstr = NULL; - table->bucketcount = 0; - table->needed = NULL; - table->hgot = NULL; - table->merge_info = NULL; - memset (&table->stab_info, 0, sizeof (table->stab_info)); - memset (&table->eh_info, 0, sizeof (table->eh_info)); - table->dynlocal = NULL; - table->runpath = NULL; - table->tls_sec = NULL; - table->tls_size = 0; - table->loaded = NULL; - table->is_relocatable_executable = FALSE; ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); table->root.type = bfd_link_elf_hash_table; @@ -1646,7 +1685,7 @@ bfd_elf_get_dyn_lib_class (bfd *abfd) } void -bfd_elf_set_dyn_lib_class (bfd *abfd, int lib_class) +bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class) { if (bfd_get_flavour (abfd) == bfd_target_elf_flavour && bfd_get_format (abfd) == bfd_object) @@ -1826,6 +1865,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) case SHT_FINI_ARRAY: /* .fini_array section. */ case SHT_PREINIT_ARRAY: /* .preinit_array section. */ case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ + case SHT_GNU_HASH: /* .gnu.hash section. */ return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); case SHT_DYNAMIC: /* Dynamic linking information. */ @@ -1877,11 +1917,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) abfd->flags |= HAS_SYMS; /* Sometimes a shared object will map in the symbol table. If - SHF_ALLOC is set, and this is a shared object, then we also - treat this section as a BFD section. We can not base the - decision purely on SHF_ALLOC, because that flag is sometimes - set in a relocatable object file, which would confuse the - linker. */ + SHF_ALLOC is set, and this is a shared object, then we also + treat this section as a BFD section. We can not base the + decision purely on SHF_ALLOC, because that flag is sometimes + set in a relocatable object file, which would confuse the + linker. */ if ((hdr->sh_flags & SHF_ALLOC) != 0 && (abfd->flags & DYNAMIC) != 0 && ! _bfd_elf_make_section_from_shdr (abfd, hdr, name, @@ -2103,13 +2143,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) abfd->flags |= HAS_RELOC; return TRUE; } - break; case SHT_GNU_verdef: elf_dynverdef (abfd) = shindex; elf_tdata (abfd)->dynverdef_hdr = *hdr; return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); - break; case SHT_GNU_versym: if (hdr->sh_entsize != sizeof (Elf_External_Versym)) @@ -2117,13 +2155,11 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) elf_dynversym (abfd) = shindex; elf_tdata (abfd)->dynversym_hdr = *hdr; return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); - break; case SHT_GNU_verneed: elf_dynverref (abfd) = shindex; elf_tdata (abfd)->dynverref_hdr = *hdr; return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); - break; case SHT_SHLIB: return TRUE; @@ -2132,7 +2168,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) /* We need a BFD section for objcopy and relocatable linking, and it's handy to have the signature available as the section name. */ - if (hdr->sh_entsize != GRP_ENTRY_SIZE) + if (! IS_VALID_GROUP_SECTION_HEADER (hdr)) return FALSE; name = group_signature (abfd, hdr); if (name == NULL) @@ -2142,7 +2178,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) if (hdr->contents != NULL) { Elf_Internal_Group *idx = (Elf_Internal_Group *) hdr->contents; - unsigned int n_elt = hdr->sh_size / 4; + unsigned int n_elt = hdr->sh_size / GRP_ENTRY_SIZE; asection *s; if (idx->flags & GRP_COMDAT) @@ -2152,19 +2188,78 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) /* We try to keep the same section order as it comes in. */ idx += n_elt; while (--n_elt != 0) - if ((s = (--idx)->shdr->bfd_section) != NULL - && elf_next_in_group (s) != NULL) - { - elf_next_in_group (hdr->bfd_section) = s; - break; - } + { + --idx; + + if (idx->shdr != NULL + && (s = idx->shdr->bfd_section) != NULL + && elf_next_in_group (s) != NULL) + { + elf_next_in_group (hdr->bfd_section) = s; + break; + } + } } break; default: + /* Possibly an attributes section. */ + if (hdr->sh_type == SHT_GNU_ATTRIBUTES + || hdr->sh_type == bed->obj_attrs_section_type) + { + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + return FALSE; + _bfd_elf_parse_attributes (abfd, hdr); + return TRUE; + } + /* Check for any processor-specific section types. */ - return bed->elf_backend_section_from_shdr (abfd, hdr, name, - shindex); + if (bed->elf_backend_section_from_shdr (abfd, hdr, name, shindex)) + return TRUE; + + if (hdr->sh_type >= SHT_LOUSER && hdr->sh_type <= SHT_HIUSER) + { + if ((hdr->sh_flags & SHF_ALLOC) != 0) + /* FIXME: How to properly handle allocated section reserved + for applications? */ + (*_bfd_error_handler) + (_("%B: don't know how to handle allocated, application " + "specific section `%s' [0x%8x]"), + abfd, name, hdr->sh_type); + else + /* Allow sections reserved for applications. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, + shindex); + } + else if (hdr->sh_type >= SHT_LOPROC + && hdr->sh_type <= SHT_HIPROC) + /* FIXME: We should handle this section. */ + (*_bfd_error_handler) + (_("%B: don't know how to handle processor specific section " + "`%s' [0x%8x]"), + abfd, name, hdr->sh_type); + else if (hdr->sh_type >= SHT_LOOS && hdr->sh_type <= SHT_HIOS) + { + /* Unrecognised OS-specific sections. */ + if ((hdr->sh_flags & SHF_OS_NONCONFORMING) != 0) + /* SHF_OS_NONCONFORMING indicates that special knowledge is + required to correctly process the section and the file should + be rejected with an error message. */ + (*_bfd_error_handler) + (_("%B: don't know how to handle OS specific section " + "`%s' [0x%8x]"), + abfd, name, hdr->sh_type); + else + /* Otherwise it should be processed. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + } + else + /* FIXME: We should handle this section. */ + (*_bfd_error_handler) + (_("%B: don't know how to handle section `%s' [0x%8x]"), + abfd, name, hdr->sh_type); + + return FALSE; } return TRUE; @@ -2224,108 +2319,111 @@ bfd_section_from_elf_index (bfd *abfd, unsigned int index) static const struct bfd_elf_special_section special_sections_b[] = { - { ".bss", 4, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".bss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_c[] = { - { ".comment", 8, 0, SHT_PROGBITS, 0 }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".comment"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_d[] = { - { ".data", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".data1", 6, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".debug", 6, 0, SHT_PROGBITS, 0 }, - { ".debug_line", 11, 0, SHT_PROGBITS, 0 }, - { ".debug_info", 11, 0, SHT_PROGBITS, 0 }, - { ".debug_abbrev", 13, 0, SHT_PROGBITS, 0 }, - { ".debug_aranges", 14, 0, SHT_PROGBITS, 0 }, - { ".dynamic", 8, 0, SHT_DYNAMIC, SHF_ALLOC }, - { ".dynstr", 7, 0, SHT_STRTAB, SHF_ALLOC }, - { ".dynsym", 7, 0, SHT_DYNSYM, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".data"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".data1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".debug"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_line"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_info"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_abbrev"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".debug_aranges"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".dynamic"), 0, SHT_DYNAMIC, SHF_ALLOC }, + { STRING_COMMA_LEN (".dynstr"), 0, SHT_STRTAB, SHF_ALLOC }, + { STRING_COMMA_LEN (".dynsym"), 0, SHT_DYNSYM, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_f[] = { - { ".fini", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".fini_array", 11, 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".fini"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".fini_array"), 0, SHT_FINI_ARRAY, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_g[] = { - { ".gnu.linkonce.b",15, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { ".got", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".gnu.version", 12, 0, SHT_GNU_versym, 0 }, - { ".gnu.version_d", 14, 0, SHT_GNU_verdef, 0 }, - { ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 }, - { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC }, - { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".gnu.linkonce.b"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".got"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".gnu.version"), 0, SHT_GNU_versym, 0 }, + { STRING_COMMA_LEN (".gnu.version_d"), 0, SHT_GNU_verdef, 0 }, + { STRING_COMMA_LEN (".gnu.version_r"), 0, SHT_GNU_verneed, 0 }, + { STRING_COMMA_LEN (".gnu.liblist"), 0, SHT_GNU_LIBLIST, SHF_ALLOC }, + { STRING_COMMA_LEN (".gnu.conflict"), 0, SHT_RELA, SHF_ALLOC }, + { STRING_COMMA_LEN (".gnu.hash"), 0, SHT_GNU_HASH, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_h[] = { - { ".hash", 5, 0, SHT_HASH, SHF_ALLOC }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".hash"), 0, SHT_HASH, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_i[] = { - { ".init", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".init_array", 11, 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, - { ".interp", 7, 0, SHT_PROGBITS, 0 }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".init"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".init_array"), 0, SHT_INIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".interp"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_l[] = { - { ".line", 5, 0, SHT_PROGBITS, 0 }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".line"), 0, SHT_PROGBITS, 0 }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_n[] = { - { ".note.GNU-stack",15, 0, SHT_PROGBITS, 0 }, - { ".note", 5, -1, SHT_NOTE, 0 }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".note.GNU-stack"), 0, SHT_PROGBITS, 0 }, + { STRING_COMMA_LEN (".note"), -1, SHT_NOTE, 0 }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_p[] = { - { ".preinit_array", 14, 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, - { ".plt", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_r[] = { - { ".rodata", 7, -2, SHT_PROGBITS, SHF_ALLOC }, - { ".rodata1", 8, 0, SHT_PROGBITS, SHF_ALLOC }, - { ".rela", 5, -1, SHT_RELA, 0 }, - { ".rel", 4, -1, SHT_REL, 0 }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".rodata"), -2, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".rodata1"), 0, SHT_PROGBITS, SHF_ALLOC }, + { STRING_COMMA_LEN (".rela"), -1, SHT_RELA, 0 }, + { STRING_COMMA_LEN (".rel"), -1, SHT_REL, 0 }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_s[] = { - { ".shstrtab", 9, 0, SHT_STRTAB, 0 }, - { ".strtab", 7, 0, SHT_STRTAB, 0 }, - { ".symtab", 7, 0, SHT_SYMTAB, 0 }, - { ".stabstr", 5, 3, SHT_STRTAB, 0 }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".shstrtab"), 0, SHT_STRTAB, 0 }, + { STRING_COMMA_LEN (".strtab"), 0, SHT_STRTAB, 0 }, + { STRING_COMMA_LEN (".symtab"), 0, SHT_SYMTAB, 0 }, + /* See struct bfd_elf_special_section declaration for the semantics of + this special case where .prefix_length != strlen (.prefix). */ + { ".stabstr", 5, 3, SHT_STRTAB, 0 }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section special_sections_t[] = { - { ".text", 5, -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, - { ".tbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, - { ".tdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".text"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR }, + { STRING_COMMA_LEN (".tbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { STRING_COMMA_LEN (".tdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_TLS }, + { NULL, 0, 0, 0, 0 } }; static const struct bfd_elf_special_section *special_sections[] = @@ -2456,10 +2554,13 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) bed = get_elf_backend_data (abfd); sec->use_rela_p = bed->default_use_rela_p; - /* When we read a file, we don't need section type and flags unless - it is a linker created section. They will be overridden in - _bfd_elf_make_section_from_shdr anyway. */ - if (abfd->direction != read_direction + /* When we read a file, we don't need to set ELF section type and + flags. They will be overridden in _bfd_elf_make_section_from_shdr + anyway. We will set ELF section type and flags for all linker + created sections. If user specifies BFD section flags, we will + set ELF section type and flags based on BFD section flags in + elf_fake_sections. */ + if ((!sec->flags && abfd->direction != read_direction) || (sec->flags & SEC_LINKER_CREATED) != 0) { ssect = (*bed->get_sec_type_attr) (abfd, sec); @@ -2470,7 +2571,7 @@ _bfd_elf_new_section_hook (bfd *abfd, asection *sec) } } - return TRUE; + return _bfd_generic_new_section_hook (abfd, sec); } /* Create a new bfd section from an ELF program header. @@ -2661,11 +2762,12 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) const struct elf_backend_data *bed = get_elf_backend_data (abfd); bfd_boolean *failedptr = failedptrarg; Elf_Internal_Shdr *this_hdr; + unsigned int sh_type; if (*failedptr) { /* We already failed; just get out of the bfd_map_over_sections - loop. */ + loop. */ return; } @@ -2704,8 +2806,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) if ((asect->flags & SEC_GROUP) != 0) this_hdr->sh_type = SHT_GROUP; else if ((asect->flags & SEC_ALLOC) != 0 - && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) - || (asect->flags & SEC_NEVER_LOAD) != 0)) + && (((asect->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + || (asect->flags & SEC_NEVER_LOAD) != 0)) this_hdr->sh_type = SHT_NOBITS; else this_hdr->sh_type = SHT_PROGBITS; @@ -2754,8 +2856,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) case SHT_GNU_verdef: this_hdr->sh_entsize = 0; /* objcopy or strip will copy over sh_info, but may not set - cverdefs. The linker will set cverdefs, but sh_info will be - zero. */ + cverdefs. The linker will set cverdefs, but sh_info will be + zero. */ if (this_hdr->sh_info == 0) this_hdr->sh_info = elf_tdata (abfd)->cverdefs; else @@ -2766,8 +2868,8 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) case SHT_GNU_verneed: this_hdr->sh_entsize = 0; /* objcopy or strip will copy over sh_info, but may not set - cverrefs. The linker will set cverrefs, but sh_info will be - zero. */ + cverrefs. The linker will set cverrefs, but sh_info will be + zero. */ if (this_hdr->sh_info == 0) this_hdr->sh_info = elf_tdata (abfd)->cverrefs; else @@ -2776,7 +2878,11 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) break; case SHT_GROUP: - this_hdr->sh_entsize = 4; + this_hdr->sh_entsize = GRP_ENTRY_SIZE; + break; + + case SHT_GNU_HASH: + this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4; break; } @@ -2814,10 +2920,18 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) } /* Check for processor-specific section types. */ + sh_type = this_hdr->sh_type; if (bed->elf_backend_fake_sections && !(*bed->elf_backend_fake_sections) (abfd, this_hdr, asect)) *failedptr = TRUE; + if (sh_type == SHT_NOBITS && asect->size != 0) + { + /* Don't change the header type from NOBITS if we are being + called for objcopy --only-keep-debug. */ + this_hdr->sh_type = sh_type; + } + /* If the section has relocs, set up a section header for the SHT_REL[A] section. If two relocation sections are required for this section, it is up to the processor-specific back-end to @@ -2939,14 +3053,14 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) d = elf_section_data (sec); if (d->this_hdr.sh_type == SHT_GROUP) - { + { if (sec->flags & SEC_LINKER_CREATED) { /* Remove the linker created SHT_GROUP sections. */ bfd_section_list_remove (abfd, sec); abfd->section_count--; } - else + else { if (section_number == SHN_LORESERVE) section_number += SHN_HIRESERVE + 1 - SHN_LORESERVE; @@ -3100,7 +3214,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) s, s->owner); /* Point to the kept section if it has the same size as the discarded one. */ - kept = _bfd_elf_check_kept_section (s); + kept = _bfd_elf_check_kept_section (s, link_info); if (kept == NULL) { bfd_set_error (bfd_error_bad_value); @@ -3133,7 +3247,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) The Intel C compiler generates SHT_IA_64_UNWIND with SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields. Hence we could get the situation - where s is NULL. */ + where s is NULL. */ const struct elf_backend_data *bed = get_elf_backend_data (abfd); if (bed->link_order_error_handler) @@ -3173,7 +3287,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) string section. We look for a section with the same name but without the trailing ``str'', and set its sh_link field to point to this section. */ - if (strncmp (sec->name, ".stab", sizeof ".stab" - 1) == 0 + if (CONST_STRNEQ (sec->name, ".stab") && strcmp (sec->name + strlen (sec->name) - 3, "str") == 0) { size_t len; @@ -3213,9 +3327,8 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) case SHT_GNU_LIBLIST: /* sh_link is the section header index of the prelink library - list - used for the dynamic entries, or the symbol table, or the - version strings. */ + list used for the dynamic entries, or the symbol table, or + the version strings. */ s = bfd_get_section_by_name (abfd, (sec->flags & SEC_ALLOC) ? ".dynstr" : ".gnu.libstr"); if (s != NULL) @@ -3223,6 +3336,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) break; case SHT_HASH: + case SHT_GNU_HASH: case SHT_GNU_versym: /* sh_link is the section header index of the symbol table this hash table or version table is for. */ @@ -3248,7 +3362,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) /* Map symbol from it's internal number to the external number, moving all local symbols to be at the head of the list. */ -static int +static bfd_boolean sym_is_global (bfd *abfd, asymbol *sym) { /* If the backend has a special mapping, use it. */ @@ -3261,6 +3375,20 @@ sym_is_global (bfd *abfd, asymbol *sym) || bfd_is_com_section (bfd_get_section (sym))); } +/* Don't output section symbols for sections that are not going to be + output. Also, don't output section symbols for reloc and other + special sections. */ + +static bfd_boolean +ignore_section_sym (bfd *abfd, asymbol *sym) +{ + return ((sym->flags & BSF_SECTION_SYM) != 0 + && (sym->value != 0 + || (sym->section->owner != abfd + && (sym->section->output_section->owner != abfd + || sym->section->output_offset != 0)))); +} + static bfd_boolean elf_map_symbols (bfd *abfd) { @@ -3301,51 +3429,29 @@ elf_map_symbols (bfd *abfd) asymbol *sym = syms[idx]; if ((sym->flags & BSF_SECTION_SYM) != 0 - && sym->value == 0) + && !ignore_section_sym (abfd, sym)) { - asection *sec; + asection *sec = sym->section; - sec = sym->section; + if (sec->owner != abfd) + sec = sec->output_section; - if (sec->owner != NULL) - { - if (sec->owner != abfd) - { - if (sec->output_offset != 0) - continue; - - sec = sec->output_section; - - /* Empty sections in the input files may have had a - section symbol created for them. (See the comment - near the end of _bfd_generic_link_output_symbols in - linker.c). If the linker script discards such - sections then we will reach this point. Since we know - that we cannot avoid this case, we detect it and skip - the abort and the assignment to the sect_syms array. - To reproduce this particular case try running the - linker testsuite test ld-scripts/weak.exp for an ELF - port that uses the generic linker. */ - if (sec->owner == NULL) - continue; - - BFD_ASSERT (sec->owner == abfd); - } - sect_syms[sec->index] = syms[idx]; - } + sect_syms[sec->index] = syms[idx]; } } /* Classify all of the symbols. */ for (idx = 0; idx < symcount; idx++) { + if (ignore_section_sym (abfd, syms[idx])) + continue; if (!sym_is_global (abfd, syms[idx])) num_locals++; else num_globals++; } - /* We will be adding a section symbol for each BFD section. Most normal + /* We will be adding a section symbol for each normal BFD section. Most sections will already have a section symbol in outsymbols, but eg. SHT_GROUP sections will not, and we need the section symbol mapped at least in that case. */ @@ -3371,6 +3477,8 @@ elf_map_symbols (bfd *abfd) asymbol *sym = syms[idx]; unsigned int i; + if (ignore_section_sym (abfd, sym)) + continue; if (!sym_is_global (abfd, sym)) i = num_locals2++; else @@ -3522,7 +3630,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, elf_tdata (abfd)->next_file_pos = off; /* Now that we know where the .strtab section goes, write it - out. */ + out. */ if (bfd_seek (abfd, hdr->sh_offset, SEEK_SET) != 0 || ! _bfd_stringtab_emit (abfd, strtab)) return FALSE; @@ -3534,6 +3642,90 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, return TRUE; } +/* Make an initial estimate of the size of the program header. If we + get the number wrong here, we'll redo section placement. */ + +static bfd_size_type +get_program_header_size (bfd *abfd, struct bfd_link_info *info) +{ + size_t segs; + asection *s; + const struct elf_backend_data *bed; + + /* 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) + { + /* 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; + } + + if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) + { + /* We need a PT_DYNAMIC segment. */ + ++segs; + + if (elf_tdata (abfd)->relro) + { + /* We need a PT_GNU_RELRO segment only when there is a + PT_DYNAMIC segment. */ + ++segs; + } + } + + if (elf_tdata (abfd)->eh_frame_hdr) + { + /* We need a PT_GNU_EH_FRAME segment. */ + ++segs; + } + + if (elf_tdata (abfd)->stack_flags) + { + /* We need a PT_GNU_STACK segment. */ + ++segs; + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && CONST_STRNEQ (s->name, ".note")) + { + /* We need a PT_NOTE segment. */ + ++segs; + } + } + + for (s = abfd->sections; s != NULL; s = s->next) + { + if (s->flags & SEC_THREAD_LOCAL) + { + /* We need a PT_TLS segment. */ + ++segs; + break; + } + } + + /* Let the backend count up any program headers it might need. */ + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_additional_program_headers) + { + int a; + + a = (*bed->elf_backend_additional_program_headers) (abfd, info); + if (a == -1) + abort (); + segs += a; + } + + return segs * bed->s->sizeof_phdr; +} + /* Create a mapping from a set of sections to a program segment. */ static struct elf_segment_map * @@ -3584,363 +3776,421 @@ _bfd_elf_make_dynamic_segment (bfd *abfd, asection *dynsec) m->p_type = PT_DYNAMIC; m->count = 1; m->sections[0] = dynsec; - + return m; } -/* Set up a mapping from BFD sections to program segments. */ +/* Possibly add or remove segments from the segment map. */ static bfd_boolean -map_sections_to_segments (bfd *abfd) +elf_modify_segment_map (bfd *abfd, struct bfd_link_info *info) { - 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; - bfd_vma last_size; - unsigned int phdr_index; - bfd_vma maxpagesize; - asection **hdrpp; - bfd_boolean phdr_in_segment = TRUE; - bfd_boolean writable; - int tls_count = 0; - asection *first_tls = NULL; - asection *dynsec, *eh_frame_hdr; - bfd_size_type amt; - - if (elf_tdata (abfd)->segment_map != NULL) - return TRUE; + struct elf_segment_map **m; + const struct elf_backend_data *bed; - if (bfd_count_sections (abfd) == 0) - return TRUE; + /* The placement algorithm assumes that non allocated sections are + not in PT_LOAD segments. We ensure this here by removing such + sections from the segment map. We also remove excluded + sections. Finally, any PT_LOAD segment without sections is + removed. */ + m = &elf_tdata (abfd)->segment_map; + while (*m) + { + unsigned int i, new_count; - /* Select the allocated sections, and sort them. */ + for (new_count = 0, i = 0; i < (*m)->count; i++) + { + if (((*m)->sections[i]->flags & SEC_EXCLUDE) == 0 + && (((*m)->sections[i]->flags & SEC_ALLOC) != 0 + || (*m)->p_type != PT_LOAD)) + { + (*m)->sections[new_count] = (*m)->sections[i]; + new_count++; + } + } + (*m)->count = new_count; - sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *)); - if (sections == NULL) - goto error_return; + if ((*m)->p_type == PT_LOAD && (*m)->count == 0) + *m = (*m)->next; + else + m = &(*m)->next; + } - i = 0; - for (s = abfd->sections; s != NULL; s = s->next) + bed = get_elf_backend_data (abfd); + if (bed->elf_backend_modify_segment_map != NULL) { - if ((s->flags & SEC_ALLOC) != 0) - { - sections[i] = s; - ++i; - } + if (!(*bed->elf_backend_modify_segment_map) (abfd, info)) + return FALSE; } - BFD_ASSERT (i <= bfd_count_sections (abfd)); - count = i; - qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); + return TRUE; +} - /* Build the mapping. */ +/* Set up a mapping from BFD sections to program segments. */ - mfirst = NULL; - pm = &mfirst; +bfd_boolean +_bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) +{ + unsigned int count; + struct elf_segment_map *m; + asection **sections = NULL; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); - /* 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) + if (elf_tdata (abfd)->segment_map == NULL + && bfd_count_sections (abfd) != 0) { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - 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; - m->includes_phdrs = 1; + asection *s; + unsigned int i; + struct elf_segment_map *mfirst; + struct elf_segment_map **pm; + asection *last_hdr; + bfd_vma last_size; + unsigned int phdr_index; + bfd_vma maxpagesize; + asection **hdrpp; + bfd_boolean phdr_in_segment = TRUE; + bfd_boolean writable; + int tls_count = 0; + asection *first_tls = NULL; + asection *dynsec, *eh_frame_hdr; + bfd_size_type amt; - *pm = m; - pm = &m->next; + /* Select the allocated sections, and sort them. */ - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) + sections = bfd_malloc2 (bfd_count_sections (abfd), sizeof (asection *)); + if (sections == NULL) goto error_return; - m->next = NULL; - m->p_type = PT_INTERP; - m->count = 1; - m->sections[0] = s; - - *pm = m; - pm = &m->next; - } - - /* 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; - last_size = 0; - phdr_index = 0; - maxpagesize = get_elf_backend_data (abfd)->maxpagesize; - writable = FALSE; - dynsec = bfd_get_section_by_name (abfd, ".dynamic"); - if (dynsec != NULL - && (dynsec->flags & SEC_LOAD) == 0) - dynsec = NULL; - - /* Deal with -Ttext or something similar such that the first section - is not adjacent to the program headers. This is an - approximation, since at this point we don't know exactly how many - program headers we will need. */ - if (count > 0) - { - bfd_size_type phdr_size; - - phdr_size = elf_tdata (abfd)->program_header_size; - if (phdr_size == 0) - phdr_size = get_elf_backend_data (abfd)->s->sizeof_phdr; - if ((abfd->flags & D_PAGED) == 0 - || sections[0]->lma < phdr_size - || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) - phdr_in_segment = FALSE; - } - - for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) - { - asection *hdr; - bfd_boolean new_segment; - - hdr = *hdrpp; - - /* See if this section and the last one will fit in the same - segment. */ - if (last_hdr == NULL) - { - /* If we don't have a segment yet, then we don't need a new - one (we build the last one after this loop). */ - new_segment = FALSE; - } - else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma) - { - /* If this section has a different relation between the - virtual address and the load address, then we need a new - segment. */ - new_segment = TRUE; - } - else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) - < BFD_ALIGN (hdr->lma, maxpagesize)) - { - /* If putting this section in this segment would force us to - skip a page in the segment, then we need a new segment. */ - new_segment = TRUE; - } - else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0 - && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0) + i = 0; + for (s = abfd->sections; s != NULL; s = s->next) { - /* We don't want to put a loadable section after a - nonloadable section in the same segment. - Consider .tbss sections as loadable for this purpose. */ - new_segment = TRUE; - } - else if ((abfd->flags & D_PAGED) == 0) - { - /* If the file is not demand paged, which means that we - don't require the sections to be correctly aligned in the - file, then there is no other reason for a new segment. */ - new_segment = FALSE; + if ((s->flags & SEC_ALLOC) != 0) + { + sections[i] = s; + ++i; + } } - else if (! writable - && (hdr->flags & SEC_READONLY) == 0 - && (((last_hdr->lma + last_size - 1) - & ~(maxpagesize - 1)) - != (hdr->lma & ~(maxpagesize - 1)))) + BFD_ASSERT (i <= bfd_count_sections (abfd)); + count = i; + + qsort (sections, (size_t) count, sizeof (asection *), elf_sort_sections); + + /* Build the mapping. */ + + mfirst = NULL; + pm = &mfirst; + + /* 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) { - /* We don't want to put a writable section in a read only - segment, unless they are on the same page in memory - anyhow. We already know that the last section does not - bring us past the current section on the page, so the - only case in which the new section is not on the same - page as the previous section is when the previous section - ends precisely on a page boundary. */ - new_segment = TRUE; + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + 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; + m->includes_phdrs = 1; + + *pm = m; + pm = &m->next; + + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_INTERP; + m->count = 1; + m->sections[0] = s; + + *pm = m; + pm = &m->next; } - else + + /* 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; + last_size = 0; + phdr_index = 0; + maxpagesize = bed->maxpagesize; + writable = FALSE; + dynsec = bfd_get_section_by_name (abfd, ".dynamic"); + if (dynsec != NULL + && (dynsec->flags & SEC_LOAD) == 0) + dynsec = NULL; + + /* Deal with -Ttext or something similar such that the first section + is not adjacent to the program headers. This is an + approximation, since at this point we don't know exactly how many + program headers we will need. */ + if (count > 0) { - /* Otherwise, we can use the same segment. */ - new_segment = FALSE; + bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size; + + if (phdr_size == (bfd_size_type) -1) + phdr_size = get_program_header_size (abfd, info); + if ((abfd->flags & D_PAGED) == 0 + || sections[0]->lma < phdr_size + || sections[0]->lma % maxpagesize < phdr_size % maxpagesize) + phdr_in_segment = FALSE; } - if (! new_segment) + for (i = 0, hdrpp = sections; i < count; i++, hdrpp++) { + asection *hdr; + bfd_boolean new_segment; + + hdr = *hdrpp; + + /* See if this section and the last one will fit in the same + segment. */ + + if (last_hdr == NULL) + { + /* If we don't have a segment yet, then we don't need a new + one (we build the last one after this loop). */ + new_segment = FALSE; + } + else if (last_hdr->lma - last_hdr->vma != hdr->lma - hdr->vma) + { + /* If this section has a different relation between the + virtual address and the load address, then we need a new + segment. */ + new_segment = TRUE; + } + else if (BFD_ALIGN (last_hdr->lma + last_size, maxpagesize) + < BFD_ALIGN (hdr->lma, maxpagesize)) + { + /* If putting this section in this segment would force us to + skip a page in the segment, then we need a new segment. */ + new_segment = TRUE; + } + else if ((last_hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == 0 + && (hdr->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) != 0) + { + /* We don't want to put a loadable section after a + nonloadable section in the same segment. + Consider .tbss sections as loadable for this purpose. */ + new_segment = TRUE; + } + else if ((abfd->flags & D_PAGED) == 0) + { + /* If the file is not demand paged, which means that we + don't require the sections to be correctly aligned in the + file, then there is no other reason for a new segment. */ + new_segment = FALSE; + } + else if (! writable + && (hdr->flags & SEC_READONLY) == 0 + && (((last_hdr->lma + last_size - 1) + & ~(maxpagesize - 1)) + != (hdr->lma & ~(maxpagesize - 1)))) + { + /* We don't want to put a writable section in a read only + segment, unless they are on the same page in memory + anyhow. We already know that the last section does not + bring us past the current section on the page, so the + only case in which the new section is not on the same + page as the previous section is when the previous section + ends precisely on a page boundary. */ + new_segment = TRUE; + } + else + { + /* Otherwise, we can use the same segment. */ + new_segment = FALSE; + } + + /* Allow interested parties a chance to override our decision. */ + if (last_hdr && info->callbacks->override_segment_assignment) + new_segment = info->callbacks->override_segment_assignment (info, abfd, hdr, last_hdr, new_segment); + + if (! new_segment) + { + if ((hdr->flags & SEC_READONLY) == 0) + writable = TRUE; + last_hdr = hdr; + /* .tbss sections effectively have zero size. */ + if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) + != SEC_THREAD_LOCAL) + last_size = hdr->size; + else + last_size = 0; + continue; + } + + /* We need a new program segment. We must create a new program + header holding all the sections from phdr_index until hdr. */ + + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); + if (m == NULL) + goto error_return; + + *pm = m; + pm = &m->next; + if ((hdr->flags & SEC_READONLY) == 0) writable = TRUE; + else + writable = FALSE; + last_hdr = hdr; /* .tbss sections effectively have zero size. */ if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) last_size = hdr->size; else last_size = 0; - continue; + phdr_index = i; + phdr_in_segment = FALSE; } - /* We need a new program segment. We must create a new program - header holding all the sections from phdr_index until hdr. */ + /* Create a final PT_LOAD program segment. */ + if (last_hdr != NULL) + { + m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); + if (m == NULL) + goto error_return; - m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); - if (m == NULL) - goto error_return; + *pm = m; + pm = &m->next; + } - *pm = m; - pm = &m->next; + /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ + if (dynsec != NULL) + { + m = _bfd_elf_make_dynamic_segment (abfd, dynsec); + if (m == NULL) + goto error_return; + *pm = m; + pm = &m->next; + } - if ((hdr->flags & SEC_READONLY) == 0) - writable = TRUE; - else - writable = FALSE; + /* For each loadable .note section, add a PT_NOTE segment. We don't + use bfd_get_section_by_name, because if we link together + nonloadable .note sections and loadable .note sections, we will + generate two .note sections in the output file. FIXME: Using + names for section types is bogus anyhow. */ + for (s = abfd->sections; s != NULL; s = s->next) + { + if ((s->flags & SEC_LOAD) != 0 + && CONST_STRNEQ (s->name, ".note")) + { + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_NOTE; + m->count = 1; + m->sections[0] = s; - last_hdr = hdr; - /* .tbss sections effectively have zero size. */ - if ((hdr->flags & (SEC_THREAD_LOCAL | SEC_LOAD)) != SEC_THREAD_LOCAL) - last_size = hdr->size; - else - last_size = 0; - phdr_index = i; - phdr_in_segment = FALSE; - } + *pm = m; + pm = &m->next; + } + if (s->flags & SEC_THREAD_LOCAL) + { + if (! tls_count) + first_tls = s; + tls_count++; + } + } - /* Create a final PT_LOAD program segment. */ - if (last_hdr != NULL) - { - m = make_mapping (abfd, sections, phdr_index, i, phdr_in_segment); - if (m == NULL) - goto error_return; + /* If there are any SHF_TLS output sections, add PT_TLS segment. */ + if (tls_count > 0) + { + int i; - *pm = m; - pm = &m->next; - } + amt = sizeof (struct elf_segment_map); + amt += (tls_count - 1) * sizeof (asection *); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_TLS; + m->count = tls_count; + /* Mandated PF_R. */ + m->p_flags = PF_R; + m->p_flags_valid = 1; + for (i = 0; i < tls_count; ++i) + { + BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); + m->sections[i] = first_tls; + first_tls = first_tls->next; + } - /* If there is a .dynamic section, throw in a PT_DYNAMIC segment. */ - if (dynsec != NULL) - { - m = _bfd_elf_make_dynamic_segment (abfd, dynsec); - if (m == NULL) - goto error_return; - *pm = m; - pm = &m->next; - } + *pm = m; + pm = &m->next; + } - /* For each loadable .note section, add a PT_NOTE segment. We don't - use bfd_get_section_by_name, because if we link together - nonloadable .note sections and loadable .note sections, we will - generate two .note sections in the output file. FIXME: Using - names for section types is bogus anyhow. */ - for (s = abfd->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LOAD) != 0 - && strncmp (s->name, ".note", 5) == 0) + /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME + segment. */ + 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 = bfd_zalloc (abfd, amt); if (m == NULL) goto error_return; m->next = NULL; - m->p_type = PT_NOTE; + m->p_type = PT_GNU_EH_FRAME; m->count = 1; - m->sections[0] = s; + m->sections[0] = eh_frame_hdr->output_section; *pm = m; pm = &m->next; } - if (s->flags & SEC_THREAD_LOCAL) - { - if (! tls_count) - first_tls = s; - tls_count++; - } - } - /* If there are any SHF_TLS output sections, add PT_TLS segment. */ - if (tls_count > 0) - { - int i; - - amt = sizeof (struct elf_segment_map); - amt += (tls_count - 1) * sizeof (asection *); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_TLS; - m->count = tls_count; - /* Mandated PF_R. */ - m->p_flags = PF_R; - m->p_flags_valid = 1; - for (i = 0; i < tls_count; ++i) + if (elf_tdata (abfd)->stack_flags) { - BFD_ASSERT (first_tls->flags & SEC_THREAD_LOCAL); - m->sections[i] = first_tls; - first_tls = first_tls->next; - } - - *pm = m; - pm = &m->next; - } + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_STACK; + m->p_flags = elf_tdata (abfd)->stack_flags; + m->p_flags_valid = 1; - /* If there is a .eh_frame_hdr section, throw in a PT_GNU_EH_FRAME - segment. */ - 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 = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_GNU_EH_FRAME; - m->count = 1; - m->sections[0] = eh_frame_hdr->output_section; + *pm = m; + pm = &m->next; + } - *pm = m; - pm = &m->next; - } + if (dynsec != NULL && elf_tdata (abfd)->relro) + { + /* We make a PT_GNU_RELRO segment only when there is a + PT_DYNAMIC segment. */ + amt = sizeof (struct elf_segment_map); + m = bfd_zalloc (abfd, amt); + if (m == NULL) + goto error_return; + m->next = NULL; + m->p_type = PT_GNU_RELRO; + m->p_flags = PF_R; + m->p_flags_valid = 1; - if (elf_tdata (abfd)->stack_flags) - { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_GNU_STACK; - m->p_flags = elf_tdata (abfd)->stack_flags; - m->p_flags_valid = 1; + *pm = m; + pm = &m->next; + } - *pm = m; - pm = &m->next; + free (sections); + elf_tdata (abfd)->segment_map = mfirst; } - if (elf_tdata (abfd)->relro) - { - amt = sizeof (struct elf_segment_map); - m = bfd_zalloc (abfd, amt); - if (m == NULL) - goto error_return; - m->next = NULL; - m->p_type = PT_GNU_RELRO; - m->p_flags = PF_R; - m->p_flags_valid = 1; - - *pm = m; - pm = &m->next; - } + if (!elf_modify_segment_map (abfd, info)) + return FALSE; - free (sections); - sections = NULL; + for (count = 0, m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + ++count; + elf_tdata (abfd)->program_header_size = count * bed->s->sizeof_phdr; - elf_tdata (abfd)->segment_map = mfirst; return TRUE; error_return: @@ -4027,7 +4277,7 @@ elf_sort_sections (const void *arg1, const void *arg2) adjustment = vma_offset + bed->maxpagesize - off_offset; else adjustment = vma_offset - off_offset; - + which can can be collapsed into the expression below. */ static file_ptr @@ -4036,154 +4286,69 @@ vma_page_aligned_bias (bfd_vma vma, ufile_ptr off, bfd_vma maxpagesize) return ((vma - off) % maxpagesize); } -static void -print_segment_map (bfd *abfd) -{ - struct elf_segment_map *m; - unsigned int i, j; - - fprintf (stderr, _(" Section to Segment mapping:\n")); - fprintf (stderr, _(" Segment Sections...\n")); - - for (i= 0, m = elf_tdata (abfd)->segment_map; - m != NULL; - i++, m = m->next) - { - const char *pt = get_segment_type (m->p_type); - char buf[32]; - - if (pt == NULL) - { - if (m->p_type >= PT_LOPROC && m->p_type <= PT_HIPROC) - sprintf (buf, "LOPROC+%7.7x", - (unsigned int) (m->p_type - PT_LOPROC)); - else if (m->p_type >= PT_LOOS && m->p_type <= PT_HIOS) - sprintf (buf, "LOOS+%7.7x", - (unsigned int) (m->p_type - PT_LOOS)); - else - snprintf (buf, sizeof (buf), "%8.8x", - (unsigned int) m->p_type); - pt = buf; - } - fprintf (stderr, " %2.2d: %14.14s: ", i, pt); - for (j = 0; j < m->count; j++) - fprintf (stderr, "%s ", m->sections [j]->name); - putc ('\n',stderr); - } -} - /* 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. */ + the file header. */ static bfd_boolean -assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) +assign_file_positions_for_load_sections (bfd *abfd, + struct bfd_link_info *link_info) { 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, voff; - bfd_vma filehdr_vaddr, filehdr_paddr; - bfd_vma phdrs_vaddr, phdrs_paddr; Elf_Internal_Phdr *p; + file_ptr off; + bfd_size_type maxpagesize; + unsigned int alloc; + unsigned int i, j; - if (elf_tdata (abfd)->segment_map == NULL) - { - if (! map_sections_to_segments (abfd)) - return FALSE; - } - else - { - /* The placement algorithm assumes that non allocated sections are - not in PT_LOAD segments. We ensure this here by removing such - sections from the segment map. We also remove excluded - sections. */ - for (m = elf_tdata (abfd)->segment_map; - m != NULL; - m = m->next) - { - unsigned int new_count; - unsigned int i; - - new_count = 0; - for (i = 0; i < m->count; i ++) - { - if ((m->sections[i]->flags & SEC_EXCLUDE) == 0 - && ((m->sections[i]->flags & SEC_ALLOC) != 0 - || m->p_type != PT_LOAD)) - { - if (i != new_count) - m->sections[new_count] = m->sections[i]; - - new_count ++; - } - } - - if (new_count != m->count) - m->count = new_count; - } - } - - if (bed->elf_backend_modify_segment_map) - { - if (! (*bed->elf_backend_modify_segment_map) (abfd, link_info)) - return FALSE; - } + if (link_info == NULL + && !elf_modify_segment_map (abfd, link_info)) + return FALSE; - count = 0; + alloc = 0; for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) - ++count; + ++alloc; elf_elfheader (abfd)->e_phoff = bed->s->sizeof_ehdr; elf_elfheader (abfd)->e_phentsize = bed->s->sizeof_phdr; - elf_elfheader (abfd)->e_phnum = count; + elf_elfheader (abfd)->e_phnum = alloc; + + if (elf_tdata (abfd)->program_header_size == (bfd_size_type) -1) + elf_tdata (abfd)->program_header_size = alloc * bed->s->sizeof_phdr; + else + BFD_ASSERT (elf_tdata (abfd)->program_header_size + >= alloc * bed->s->sizeof_phdr); - if (count == 0) + if (alloc == 0) { elf_tdata (abfd)->next_file_pos = bed->s->sizeof_ehdr; return TRUE; } - /* 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) - (_("%B: Not enough room for program headers (allocated %u, need %u)"), - abfd, alloc, count)); - print_segment_map (abfd); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - - if (alloc == 0) - alloc = count; - phdrs = bfd_alloc2 (abfd, alloc, sizeof (Elf_Internal_Phdr)); + elf_tdata (abfd)->phdr = phdrs; if (phdrs == NULL) return FALSE; + maxpagesize = 1; + if ((abfd->flags & D_PAGED) != 0) + maxpagesize = bed->maxpagesize; + off = bed->s->sizeof_ehdr; off += alloc * bed->s->sizeof_phdr; - filehdr_vaddr = 0; - filehdr_paddr = 0; - phdrs_vaddr = 0; - phdrs_paddr = 0; - - for (m = elf_tdata (abfd)->segment_map, p = phdrs; + for (m = elf_tdata (abfd)->segment_map, p = phdrs, j = 0; m != NULL; - m = m->next, p++) + m = m->next, p++, j++) { - unsigned int i; asection **secpp; + bfd_vma off_adjust; + bfd_boolean no_contents; /* If elf_segment_map is not from map_sections_to_segments, the - sections may not be correctly ordered. NOTE: sorting should + sections may not be correctly ordered. NOTE: sorting should not be done to the PT_NOTE section of a corefile, which may contain several pseudo-sections artificially created by bfd. Sorting these pseudo-sections breaks things badly. */ @@ -4197,58 +4362,109 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) number of sections with contents contributing to both p_filesz and p_memsz, followed by a number of sections with no contents that just contribute to p_memsz. In this loop, OFF tracks next - available file offset for PT_LOAD and PT_NOTE segments. VOFF is - an adjustment we use for segments that have no file contents - but need zero filled memory allocation. */ - voff = 0; + available file offset for PT_LOAD and PT_NOTE segments. */ p->p_type = m->p_type; p->p_flags = m->p_flags; + if (m->count == 0) + p->p_vaddr = 0; + else + p->p_vaddr = m->sections[0]->vma - m->p_vaddr_offset; + + 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 - m->p_vaddr_offset; + + if (p->p_type == PT_LOAD + && (abfd->flags & D_PAGED) != 0) + { + /* p_align in demand paged PT_LOAD segments effectively stores + the maximum page size. When copying an executable with + objcopy, we set m->p_align from the input file. Use this + value for maxpagesize rather than bed->maxpagesize, which + may be different. Note that we use maxpagesize for PT_TLS + segment alignment later in this function, so we are relying + on at least one PT_LOAD segment appearing before a PT_TLS + segment. */ + if (m->p_align_valid) + maxpagesize = m->p_align; + + p->p_align = maxpagesize; + } + else if (m->count == 0) + p->p_align = 1 << bed->s->log_file_align; + else if (m->p_align_valid) + p->p_align = m->p_align; + else + p->p_align = 0; + + no_contents = FALSE; + off_adjust = 0; if (p->p_type == PT_LOAD && m->count > 0) { bfd_size_type align; - bfd_vma adjust; unsigned int align_power = 0; - for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + if (m->p_align_valid) + align = p->p_align; + else { - unsigned int secalign; + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + unsigned int secalign; - secalign = bfd_get_section_alignment (abfd, *secpp); - if (secalign > align_power) - align_power = secalign; + secalign = bfd_get_section_alignment (abfd, *secpp); + if (secalign > align_power) + align_power = secalign; + } + align = (bfd_size_type) 1 << align_power; + if (align < maxpagesize) + align = maxpagesize; } - align = (bfd_size_type) 1 << align_power; - - if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > align) - align = bed->maxpagesize; - adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align); - off += adjust; - if (adjust != 0 - && !m->includes_filehdr - && !m->includes_phdrs - && (ufile_ptr) off >= align) + for (i = 0; i < m->count; i++) + if ((m->sections[i]->flags & (SEC_LOAD | SEC_HAS_CONTENTS)) == 0) + /* If we aren't making room for this section, then + it must be SHT_NOBITS regardless of what we've + set via struct bfd_elf_special_section. */ + elf_section_type (m->sections[i]) = SHT_NOBITS; + + /* Find out whether this segment contains any loadable + sections. If the first section isn't loadable, the same + holds for any other sections. */ + i = 0; + while (elf_section_type (m->sections[i]) == SHT_NOBITS) { - /* If the first section isn't loadable, the same holds for - any other sections. Since the segment won't need file - space, we can make p_offset overlap some prior segment. - However, .tbss is special. If a segment starts with - .tbss, we need to look at the next section to decide - whether the segment has any loadable sections. */ - i = 0; - while ((m->sections[i]->flags & SEC_LOAD) == 0) + /* If a segment starts with .tbss, we need to look + at the next section to decide whether the segment + has any loadable sections. */ + if ((elf_section_flags (m->sections[i]) & SHF_TLS) == 0 + || ++i >= m->count) { - if ((m->sections[i]->flags & SEC_THREAD_LOCAL) == 0 - || ++i >= m->count) - { - off -= adjust; - voff = adjust - align; - break; - } + no_contents = TRUE; + break; } } + + off_adjust = vma_page_aligned_bias (m->sections[0]->vma, off, align); + off += off_adjust; + if (no_contents) + { + /* We shouldn't need to align the segment on disk since + the segment doesn't need file space, but the gABI + arguably requires the alignment and glibc ld.so + checks it. So to comply with the alignment + requirement but not waste file space, we adjust + p_offset for just this segment. (OFF_ADJUST is + subtracted from OFF later.) This may put p_offset + past the end of file, but that shouldn't matter. */ + } + else + off_adjust = 0; } /* Make sure the .dynamic section is the first section in the PT_DYNAMIC segment. */ @@ -4263,35 +4479,14 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) return FALSE; } - if (m->count == 0) - p->p_vaddr = 0; - else - p->p_vaddr = m->sections[0]->vma; - - 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 - && (abfd->flags & D_PAGED) != 0) - p->p_align = bed->maxpagesize; - else if (m->count == 0) - p->p_align = 1 << bed->s->log_file_align; - else - p->p_align = 0; - p->p_offset = 0; p->p_filesz = 0; p->p_memsz = 0; if (m->includes_filehdr) { - if (! m->p_flags_valid) + if (!m->p_flags_valid) p->p_flags |= PF_R; - p->p_offset = 0; p->p_filesz = bed->s->sizeof_ehdr; p->p_memsz = bed->s->sizeof_ehdr; if (m->count > 0) @@ -4308,30 +4503,17 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) } p->p_vaddr -= off; - if (! m->p_paddr_valid) + if (!m->p_paddr_valid) p->p_paddr -= off; } - if (p->p_type == PT_LOAD) - { - filehdr_vaddr = p->p_vaddr; - filehdr_paddr = p->p_paddr; - } } if (m->includes_phdrs) { - if (! m->p_flags_valid) + if (!m->p_flags_valid) p->p_flags |= PF_R; - if (m->includes_filehdr) - { - if (p->p_type == PT_LOAD) - { - phdrs_vaddr = p->p_vaddr + bed->s->sizeof_ehdr; - phdrs_paddr = p->p_paddr + bed->s->sizeof_ehdr; - } - } - else + if (!m->includes_filehdr) { p->p_offset = bed->s->sizeof_ehdr; @@ -4339,17 +4521,9 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) { BFD_ASSERT (p->p_type == PT_LOAD); p->p_vaddr -= off - p->p_offset; - if (! m->p_paddr_valid) + if (!m->p_paddr_valid) p->p_paddr -= off - p->p_offset; } - - if (p->p_type == PT_LOAD) - { - phdrs_vaddr = p->p_vaddr; - phdrs_paddr = p->p_paddr; - } - else - phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; } p->p_filesz += alloc * bed->s->sizeof_phdr; @@ -4359,36 +4533,44 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (p->p_type == PT_LOAD || (p->p_type == PT_NOTE && bfd_get_format (abfd) == bfd_core)) { - if (! m->includes_filehdr && ! m->includes_phdrs) - p->p_offset = off + voff; + if (!m->includes_filehdr && !m->includes_phdrs) + p->p_offset = off; else { file_ptr adjust; adjust = off - (p->p_offset + p->p_filesz); - p->p_filesz += adjust; + if (!no_contents) + p->p_filesz += adjust; p->p_memsz += adjust; } } + /* Set up p_filesz, p_memsz, p_align and p_flags from the section + maps. Set filepos for sections in PT_LOAD segments, and in + core files, for sections in PT_NOTE segments. + assign_file_positions_for_non_load_sections will set filepos + for other sections and update p_filesz for other segments. */ for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) { asection *sec; - flagword flags; bfd_size_type align; + Elf_Internal_Shdr *this_hdr; sec = *secpp; - flags = sec->flags; - align = 1 << bfd_get_section_alignment (abfd, sec); + this_hdr = &elf_section_data (sec)->this_hdr; + align = (bfd_size_type) 1 << bfd_get_section_alignment (abfd, sec); if (p->p_type == PT_LOAD || p->p_type == PT_TLS) { - bfd_signed_vma adjust; + bfd_signed_vma adjust = sec->lma - (p->p_paddr + p->p_memsz); - if ((flags & SEC_LOAD) != 0) + if (this_hdr->sh_type != SHT_NOBITS + || ((this_hdr->sh_flags & SHF_ALLOC) != 0 + && ((this_hdr->sh_flags & SHF_TLS) == 0 + || p->p_type == PT_TLS))) { - adjust = sec->lma - (p->p_paddr + p->p_filesz); if (adjust < 0) { (*_bfd_error_handler) @@ -4396,24 +4578,13 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) abfd, sec, (unsigned long) sec->lma); adjust = 0; } - off += adjust; - p->p_filesz += adjust; - p->p_memsz += adjust; - } - /* .tbss is special. It doesn't contribute to p_memsz of - normal segments. */ - else if ((flags & SEC_THREAD_LOCAL) == 0 - || p->p_type == PT_TLS) - { - /* The section VMA must equal the file position - modulo the page size. */ - bfd_size_type page = align; - if ((abfd->flags & D_PAGED) != 0 && bed->maxpagesize > page) - page = bed->maxpagesize; - adjust = vma_page_aligned_bias (sec->vma, - p->p_vaddr + p->p_memsz, - page); p->p_memsz += adjust; + + if (this_hdr->sh_type != SHT_NOBITS) + { + off += adjust; + p->p_filesz += adjust; + } } } @@ -4423,9 +4594,9 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) everything. */ if (i == 0) { - sec->filepos = off; - off += sec->size; - p->p_filesz = sec->size; + this_hdr->sh_offset = sec->filepos = off; + off += this_hdr->sh_size; + p->p_filesz = this_hdr->sh_size; p->p_memsz = 0; p->p_align = 1; } @@ -4442,96 +4613,200 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) { if (p->p_type == PT_LOAD) { - sec->filepos = off; - /* FIXME: The SEC_HAS_CONTENTS test here dates back to - 1997, and the exact reason for it isn't clear. One - plausible explanation is that it is to work around - a problem we have with linker scripts using data - statements in NOLOAD sections. I don't think it - makes a great deal of sense to have such a section - assigned to a PT_LOAD segment, but apparently - people do this. The data statement results in a - bfd_data_link_order being built, and these need - section contents to write into. Eventually, we get - to _bfd_elf_write_object_contents which writes any - section with contents to the output. Make room - here for the write, so that following segments are - not trashed. */ - if ((flags & SEC_LOAD) != 0 - || (flags & SEC_HAS_CONTENTS) != 0) - off += sec->size; + this_hdr->sh_offset = sec->filepos = off; + if (this_hdr->sh_type != SHT_NOBITS) + off += this_hdr->sh_size; } - if ((flags & SEC_LOAD) != 0) + if (this_hdr->sh_type != SHT_NOBITS) { - p->p_filesz += sec->size; - p->p_memsz += sec->size; + p->p_filesz += this_hdr->sh_size; + /* A load section without SHF_ALLOC is something like + a note section in a PT_NOTE segment. These take + file space but are not loaded into memory. */ + if ((this_hdr->sh_flags & SHF_ALLOC) != 0) + p->p_memsz += this_hdr->sh_size; } - /* PR ld/594: Sections in note segments which are not loaded - contribute to the file size but not the in-memory size. */ - else if (p->p_type == PT_NOTE - && (flags & SEC_HAS_CONTENTS) != 0) - p->p_filesz += sec->size; - - /* .tbss is special. It doesn't contribute to p_memsz of - normal segments. */ - else if ((flags & SEC_THREAD_LOCAL) == 0 - || p->p_type == PT_TLS) - p->p_memsz += sec->size; - - if (p->p_type == PT_TLS - && sec->size == 0 - && (sec->flags & SEC_HAS_CONTENTS) == 0) + else if ((this_hdr->sh_flags & SHF_ALLOC) != 0) { - struct bfd_link_order *o = sec->map_tail.link_order; - if (o != NULL) - p->p_memsz += o->offset + o->size; + if (p->p_type == PT_TLS) + p->p_memsz += this_hdr->sh_size; + + /* .tbss is special. It doesn't contribute to p_memsz of + normal segments. */ + else if ((this_hdr->sh_flags & SHF_TLS) == 0) + p->p_memsz += this_hdr->sh_size; } - if (align > p->p_align - && (p->p_type != PT_LOAD || (abfd->flags & D_PAGED) == 0)) + if (p->p_type == PT_GNU_RELRO) + p->p_align = 1; + else if (align > p->p_align + && !m->p_align_valid + && (p->p_type != PT_LOAD + || (abfd->flags & D_PAGED) == 0)) p->p_align = align; } - if (! m->p_flags_valid) + if (!m->p_flags_valid) { p->p_flags |= PF_R; - if ((flags & SEC_CODE) != 0) + if ((this_hdr->sh_flags & SHF_EXECINSTR) != 0) p->p_flags |= PF_X; - if ((flags & SEC_READONLY) == 0) + if ((this_hdr->sh_flags & SHF_WRITE) != 0) p->p_flags |= PF_W; } } + off -= off_adjust; + + /* Check that all sections are in a PT_LOAD segment. + Don't check funky gdb generated core files. */ + if (p->p_type == PT_LOAD && bfd_get_format (abfd) != bfd_core) + for (i = 0, secpp = m->sections; i < m->count; i++, secpp++) + { + Elf_Internal_Shdr *this_hdr; + asection *sec; + + sec = *secpp; + this_hdr = &(elf_section_data(sec)->this_hdr); + if (this_hdr->sh_size != 0 + && !ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, p)) + { + (*_bfd_error_handler) + (_("%B: section `%A' can't be allocated in segment %d"), + abfd, sec, j); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + } + } + + elf_tdata (abfd)->next_file_pos = off; + return TRUE; +} + +/* Assign file positions for the other sections. */ + +static bfd_boolean +assign_file_positions_for_non_load_sections (bfd *abfd, + struct bfd_link_info *link_info) +{ + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + Elf_Internal_Shdr **i_shdrpp; + Elf_Internal_Shdr **hdrpp; + Elf_Internal_Phdr *phdrs; + Elf_Internal_Phdr *p; + struct elf_segment_map *m; + bfd_vma filehdr_vaddr, filehdr_paddr; + bfd_vma phdrs_vaddr, phdrs_paddr; + file_ptr off; + unsigned int num_sec; + unsigned int i; + unsigned int count; + + i_shdrpp = elf_elfsections (abfd); + num_sec = elf_numsections (abfd); + off = elf_tdata (abfd)->next_file_pos; + for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + { + struct elf_obj_tdata *tdata = elf_tdata (abfd); + Elf_Internal_Shdr *hdr; + + hdr = *hdrpp; + if (hdr->bfd_section != NULL + && (hdr->bfd_section->filepos != 0 + || (hdr->sh_type == SHT_NOBITS + && hdr->contents == NULL))) + BFD_ASSERT (hdr->sh_offset == hdr->bfd_section->filepos); + else if ((hdr->sh_flags & SHF_ALLOC) != 0) + { + if (hdr->sh_size != 0) + ((*_bfd_error_handler) + (_("%B: warning: allocated section `%s' not in segment"), + abfd, + (hdr->bfd_section == NULL + ? "*unknown*" + : hdr->bfd_section->name))); + /* We don't need to page align empty sections. */ + if ((abfd->flags & D_PAGED) != 0 && hdr->sh_size != 0) + off += vma_page_aligned_bias (hdr->sh_addr, off, + bed->maxpagesize); + else + off += vma_page_aligned_bias (hdr->sh_addr, off, + hdr->sh_addralign); + off = _bfd_elf_assign_file_position_for_section (hdr, off, + FALSE); + } + else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) + && hdr->bfd_section == NULL) + || hdr == i_shdrpp[tdata->symtab_section] + || hdr == i_shdrpp[tdata->symtab_shndx_section] + || hdr == i_shdrpp[tdata->strtab_section]) + hdr->sh_offset = -1; + else + off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + + if (i == SHN_LORESERVE - 1) + { + i += SHN_HIRESERVE + 1 - SHN_LORESERVE; + hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE; + } } /* Now that we have set the section file positions, we can set up the file positions for the non PT_LOAD segments. */ + count = 0; + filehdr_vaddr = 0; + filehdr_paddr = 0; + phdrs_vaddr = bed->maxpagesize + bed->s->sizeof_ehdr; + phdrs_paddr = 0; + phdrs = elf_tdata (abfd)->phdr; for (m = elf_tdata (abfd)->segment_map, p = phdrs; m != NULL; m = m->next, p++) { - if (p->p_type != PT_LOAD && m->count > 0) + ++count; + if (p->p_type != PT_LOAD) + continue; + + if (m->includes_filehdr) { - BFD_ASSERT (! m->includes_filehdr && ! m->includes_phdrs); - /* If the section has not yet been assigned a file position, - do so now. The ARM BPABI requires that .dynamic section - not be marked SEC_ALLOC because it is not part of any - PT_LOAD segment, so it will not be processed above. */ - if (p->p_type == PT_DYNAMIC && m->sections[0]->filepos == 0) + filehdr_vaddr = p->p_vaddr; + filehdr_paddr = p->p_paddr; + } + if (m->includes_phdrs) + { + phdrs_vaddr = p->p_vaddr; + phdrs_paddr = p->p_paddr; + if (m->includes_filehdr) { - unsigned int i; - Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); - - i = 1; - while (i_shdrpp[i]->bfd_section != m->sections[0]) - ++i; - off = (_bfd_elf_assign_file_position_for_section - (i_shdrpp[i], off, TRUE)); - p->p_filesz = m->sections[0]->size; + phdrs_vaddr += bed->s->sizeof_ehdr; + phdrs_paddr += bed->s->sizeof_ehdr; } - p->p_offset = m->sections[0]->filepos; } - if (m->count == 0) + } + + for (m = elf_tdata (abfd)->segment_map, p = phdrs; + m != NULL; + m = m->next, p++) + { + if (m->count != 0) + { + if (p->p_type != PT_LOAD + && (p->p_type != PT_NOTE || bfd_get_format (abfd) != bfd_core)) + { + Elf_Internal_Shdr *hdr; + BFD_ASSERT (!m->includes_filehdr && !m->includes_phdrs); + + hdr = &elf_section_data (m->sections[m->count - 1])->this_hdr; + p->p_filesz = (m->sections[m->count - 1]->filepos + - m->sections[0]->filepos); + if (hdr->sh_type != SHT_NOBITS) + p->p_filesz += hdr->sh_size; + + p->p_offset = m->sections[0]->filepos; + } + } + else { if (m->includes_filehdr) { @@ -4554,8 +4829,8 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) if (lp->p_type == PT_LOAD && lp->p_vaddr <= link_info->relro_end && lp->p_vaddr >= link_info->relro_start - && lp->p_vaddr + lp->p_filesz - >= link_info->relro_end) + && (lp->p_vaddr + lp->p_filesz + >= link_info->relro_end)) break; } @@ -4579,131 +4854,11 @@ assign_file_positions_for_segments (bfd *abfd, struct bfd_link_info *link_info) } } - /* Clear out any program headers we allocated but did not use. */ - for (; count < alloc; count++, p++) - { - memset (p, 0, sizeof *p); - p->p_type = PT_NULL; - } - - elf_tdata (abfd)->phdr = phdrs; - elf_tdata (abfd)->next_file_pos = off; - /* Write out the program headers. */ - if (bfd_seek (abfd, (bfd_signed_vma) 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 (bfd *abfd) -{ - size_t segs; - asection *s; - const 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; - - if (elf_tdata (abfd)->segment_map != NULL) - { - struct elf_segment_map *m; - - segs = 0; - for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) - ++segs; - elf_tdata (abfd)->program_header_size = segs * bed->s->sizeof_phdr; - return elf_tdata (abfd)->program_header_size; - } - - /* 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) - { - /* 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; - } - - if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) - { - /* We need a PT_DYNAMIC segment. */ - ++segs; - } - - if (elf_tdata (abfd)->eh_frame_hdr) - { - /* We need a PT_GNU_EH_FRAME segment. */ - ++segs; - } - - if (elf_tdata (abfd)->stack_flags) - { - /* We need a PT_GNU_STACK segment. */ - ++segs; - } - - if (elf_tdata (abfd)->relro) - { - /* We need a PT_GNU_RELRO segment. */ - ++segs; - } - - for (s = abfd->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LOAD) != 0 - && strncmp (s->name, ".note", 5) == 0) - { - /* We need a PT_NOTE segment. */ - ++segs; - } - } - - for (s = abfd->sections; s != NULL; s = s->next) - { - if (s->flags & SEC_THREAD_LOCAL) - { - /* We need a PT_TLS segment. */ - ++segs; - break; - } - } - - /* Let the backend count up any program headers it might need. */ - if (bed->elf_backend_additional_program_headers) - { - int a; - - a = (*bed->elf_backend_additional_program_headers) (abfd); - if (a == -1) - abort (); - segs += a; - } - - 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 _bfd_elf_compute_section_file_positions. All the section sizes and VMAs must be known before this is called. @@ -4722,16 +4877,16 @@ static bfd_boolean assign_file_positions_except_relocs (bfd *abfd, struct bfd_link_info *link_info) { - struct elf_obj_tdata * const tdata = elf_tdata (abfd); - Elf_Internal_Ehdr * const i_ehdrp = elf_elfheader (abfd); - Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); - unsigned int num_sec = elf_numsections (abfd); + struct elf_obj_tdata *tdata = elf_tdata (abfd); + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); file_ptr off; const struct elf_backend_data *bed = get_elf_backend_data (abfd); if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 && bfd_get_format (abfd) != bfd_core) { + Elf_Internal_Shdr ** const i_shdrpp = elf_elfsections (abfd); + unsigned int num_sec = elf_numsections (abfd); Elf_Internal_Shdr **hdrpp; unsigned int i; @@ -4766,58 +4921,30 @@ assign_file_positions_except_relocs (bfd *abfd, } else { - unsigned int i; - Elf_Internal_Shdr **hdrpp; + unsigned int alloc; /* Assign file positions for the loaded sections based on the - assignment of sections to segments. */ - if (! assign_file_positions_for_segments (abfd, link_info)) + assignment of sections to segments. */ + if (!assign_file_positions_for_load_sections (abfd, link_info)) return FALSE; - /* Assign file positions for the other sections. */ + /* And for non-load sections. */ + if (!assign_file_positions_for_non_load_sections (abfd, link_info)) + return FALSE; - off = elf_tdata (abfd)->next_file_pos; - for (i = 1, hdrpp = i_shdrpp + 1; i < num_sec; i++, hdrpp++) + if (bed->elf_backend_modify_program_headers != NULL) { - Elf_Internal_Shdr *hdr; + if (!(*bed->elf_backend_modify_program_headers) (abfd, link_info)) + return FALSE; + } - hdr = *hdrpp; - 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 (hdr->sh_size != 0) - ((*_bfd_error_handler) - (_("%B: warning: allocated section `%s' not in segment"), - abfd, - (hdr->bfd_section == NULL - ? "*unknown*" - : hdr->bfd_section->name))); - if ((abfd->flags & D_PAGED) != 0) - off += vma_page_aligned_bias (hdr->sh_addr, off, - bed->maxpagesize); - else - off += vma_page_aligned_bias (hdr->sh_addr, off, - hdr->sh_addralign); - off = _bfd_elf_assign_file_position_for_section (hdr, off, - FALSE); - } - else if (((hdr->sh_type == SHT_REL || hdr->sh_type == SHT_RELA) - && hdr->bfd_section == NULL) - || hdr == i_shdrpp[tdata->symtab_section] - || hdr == i_shdrpp[tdata->symtab_shndx_section] - || hdr == i_shdrpp[tdata->strtab_section]) - hdr->sh_offset = -1; - else - off = _bfd_elf_assign_file_position_for_section (hdr, off, TRUE); + /* Write out the program headers. */ + alloc = tdata->program_header_size / bed->s->sizeof_phdr; + if (bfd_seek (abfd, (bfd_signed_vma) bed->s->sizeof_ehdr, SEEK_SET) != 0 + || bed->s->write_out_phdrs (abfd, tdata->phdr, alloc) != 0) + return FALSE; - if (i == SHN_LORESERVE - 1) - { - i += SHN_HIRESERVE + 1 - SHN_LORESERVE; - hdrpp += SHN_HIRESERVE + 1 - SHN_LORESERVE; - } - } + off = tdata->next_file_pos; } /* Place the section headers. */ @@ -4825,7 +4952,7 @@ assign_file_positions_except_relocs (bfd *abfd, i_ehdrp->e_shoff = off; off += i_ehdrp->e_shnum * i_ehdrp->e_shentsize; - elf_tdata (abfd)->next_file_pos = off; + tdata->next_file_pos = off; return TRUE; } @@ -4994,7 +5121,7 @@ _bfd_elf_write_object_contents (bfd *abfd) /* Write out the section header names. */ if (elf_shstrtab (abfd) != NULL && (bfd_seek (abfd, elf_tdata (abfd)->shstrtab_hdr.sh_offset, SEEK_SET) != 0 - || ! _bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))) + || !_bfd_elf_strtab_emit (abfd, elf_shstrtab (abfd)))) return FALSE; if (bed->elf_backend_final_write_processing) @@ -5066,13 +5193,14 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) && (flags & BSF_SECTION_SYM) && asym_ptr->section) { + asection *sec; int indx; - if (asym_ptr->section->output_section != NULL) - indx = asym_ptr->section->output_section->index; - else - indx = asym_ptr->section->index; - if (indx < elf_num_section_syms (abfd) + sec = asym_ptr->section; + if (sec->owner != abfd && sec->output_section != NULL) + sec = sec->output_section; + if (sec->owner == abfd + && (indx = sec->index) < elf_num_section_syms (abfd) && elf_section_syms (abfd)[indx] != NULL) asym_ptr->udata.i = elf_section_syms (abfd)[indx]->udata.i; } @@ -5082,7 +5210,7 @@ _bfd_elf_symbol_from_bfd_symbol (bfd *abfd, asymbol **asym_ptr_ptr) if (idx == 0) { /* This case can occur when using --strip-symbol on a symbol - which is used in a relocation entry. */ + which is used in a relocation entry. */ (*_bfd_error_handler) (_("%B: symbol `%s' required but not present"), abfd, bfd_asymbol_name (asym_ptr)); @@ -5161,7 +5289,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) && bfd_get_format (ibfd) == bfd_core \ && s->vma == 0 && s->lma == 0 \ && (bfd_vma) s->filepos >= p->p_offset \ - && ((bfd_vma) s->filepos + s->size \ + && ((bfd_vma) s->filepos + s->size \ <= p->p_offset + p->p_filesz)) /* The complicated case when p_vaddr is 0 is to handle the Solaris @@ -5175,13 +5303,13 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) && (s->flags & SEC_HAS_CONTENTS) != 0 \ && s->size > 0 \ && (bfd_vma) s->filepos >= p->p_offset \ - && ((bfd_vma) s->filepos + s->size \ + && ((bfd_vma) s->filepos + s->size \ <= p->p_offset + p->p_filesz)) /* Decide if the given section should be included in the given segment. A section will be included if: 1. It is within the address space of the segment -- we use the LMA - if that is set for the segment and the VMA otherwise, + if that is set for the segment and the VMA otherwise, 2. It is an allocated segment, 3. There is an output section associated with it, 4. The section has not already been allocated to a previous segment. @@ -5189,14 +5317,13 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) 6. PT_TLS segment includes only SHF_TLS sections. 7. SHF_TLS sections are only in PT_TLS or PT_LOAD segments. 8. PT_DYNAMIC should not contain empty sections at the beginning - (with the possible exception of .dynamic). */ -#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \ + (with the possible exception of .dynamic). */ +#define IS_SECTION_IN_INPUT_SEGMENT(section, segment, bed) \ ((((segment->p_paddr \ ? IS_CONTAINED_BY_LMA (section, segment, segment->p_paddr) \ : IS_CONTAINED_BY_VMA (section, segment)) \ && (section->flags & SEC_ALLOC) != 0) \ || IS_COREFILE_NOTE (segment, section)) \ - && section->output_section != NULL \ && segment->p_type != PT_GNU_STACK \ && (segment->p_type != PT_TLS \ || (section->flags & SEC_THREAD_LOCAL)) \ @@ -5206,12 +5333,18 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) && (segment->p_type != PT_DYNAMIC \ || SECTION_SIZE (section, segment) > 0 \ || (segment->p_paddr \ - ? segment->p_paddr != section->lma \ - : segment->p_vaddr != section->vma) \ + ? segment->p_paddr != section->lma \ + : segment->p_vaddr != section->vma) \ || (strcmp (bfd_get_section_name (ibfd, section), ".dynamic") \ - == 0)) \ + == 0)) \ && ! section->segment_mark) +/* If the output section of a section in the input segment is NULL, + it is removed from the corresponding output segment. */ +#define INCLUDE_SECTION_IN_SEGMENT(section, segment, bed) \ + (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed) \ + && section->output_section != NULL) + /* Returns TRUE iff seg1 starts after the end of seg2. */ #define SEGMENT_AFTER_SEGMENT(seg1, seg2, field) \ (seg1->field >= SEGMENT_END (seg2, seg2->field)) @@ -5224,9 +5357,9 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) LMA. */ #define SEGMENT_OVERLAPS(seg1, seg2) \ ( !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_vaddr) \ - || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \ + || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_vaddr)) \ && !(SEGMENT_AFTER_SEGMENT (seg1, seg2, p_paddr) \ - || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr))) + || SEGMENT_AFTER_SEGMENT (seg2, seg1, p_paddr))) /* Initialise the segment mark field. */ for (section = ibfd->sections; section != NULL; section = section->next) @@ -5269,7 +5402,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) if (segment2->p_vaddr < segment->p_vaddr) { /* Extend SEGMENT2 to include SEGMENT and then delete - SEGMENT. */ + SEGMENT. */ extra_length = SEGMENT_END (segment, segment->p_vaddr) - SEGMENT_END (segment2, segment2->p_vaddr); @@ -5290,7 +5423,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) else { /* Extend SEGMENT to include SEGMENT2 and then delete - SEGMENT2. */ + SEGMENT2. */ extra_length = SEGMENT_END (segment2, segment2->p_vaddr) - SEGMENT_END (segment, segment->p_vaddr); @@ -5319,22 +5452,33 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) bfd_vma suggested_lma; unsigned int j; bfd_size_type amt; + asection * first_section; if (segment->p_type == PT_NULL) continue; + first_section = NULL; /* Compute how many sections might be placed into this segment. */ for (section = ibfd->sections, section_count = 0; section != NULL; section = section->next) - if (INCLUDE_SECTION_IN_SEGMENT (section, segment, bed)) - ++section_count; + { + /* Find the first section in the input segment, which may be + removed from the corresponding output segment. */ + if (IS_SECTION_IN_INPUT_SEGMENT (section, segment, bed)) + { + if (first_section == NULL) + first_section = section; + if (section->output_section != NULL) + ++section_count; + } + } /* Allocate a segment map big enough to contain all of the sections we have selected. */ amt = sizeof (struct elf_segment_map); amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); - map = bfd_alloc (obfd, amt); + map = bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -5344,8 +5488,15 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) map->p_type = segment->p_type; map->p_flags = segment->p_flags; map->p_flags_valid = 1; - map->p_paddr = segment->p_paddr; - map->p_paddr_valid = 1; + + /* If the first section in the input segment is removed, there is + no need to preserve segment physical address in the corresponding + output segment. */ + if (!first_section || first_section->output_section != NULL) + { + map->p_paddr = segment->p_paddr; + map->p_paddr_valid = 1; + } /* Determine if this segment contains the ELF file header and if it contains the program headers themselves. */ @@ -5462,8 +5613,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) if (IS_CONTAINED_BY_LMA (output_section, segment, map->p_paddr) || IS_COREFILE_NOTE (segment, section) || (bed->want_p_paddr_set_to_zero && - IS_CONTAINED_BY_VMA (output_section, segment)) - ) + IS_CONTAINED_BY_VMA (output_section, segment))) { if (matching_lma == 0) matching_lma = output_section->lma; @@ -5492,6 +5642,13 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) *pointer_to_map = map; pointer_to_map = &map->next; + if (matching_lma != map->p_paddr + && !map->includes_filehdr && !map->includes_phdrs) + /* There is some padding before the first section in the + segment. So, we must account for that in the output + segment's vma. */ + map->p_vaddr_offset = matching_lma - map->p_paddr; + free (sections); continue; } @@ -5675,6 +5832,7 @@ rewrite_elf_program_header (bfd *ibfd, bfd *obfd) #undef IS_CONTAINED_BY_LMA #undef IS_COREFILE_NOTE #undef IS_SOLARIS_PT_INTERP +#undef IS_SECTION_IN_INPUT_SEGMENT #undef INCLUDE_SECTION_IN_SEGMENT #undef SEGMENT_AFTER_SEGMENT #undef SEGMENT_OVERLAPS @@ -5709,6 +5867,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) unsigned int section_count; bfd_size_type amt; Elf_Internal_Shdr *this_hdr; + asection *first_section = NULL; /* FIXME: Do we need to copy PT_NULL segment? */ if (segment->p_type == PT_NULL) @@ -5721,7 +5880,11 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) { this_hdr = &(elf_section_data(section)->this_hdr); if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) - section_count++; + { + if (!first_section) + first_section = section; + section_count++; + } } /* Allocate a segment map big enough to contain @@ -5729,7 +5892,7 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) amt = sizeof (struct elf_segment_map); if (section_count != 0) amt += ((bfd_size_type) section_count - 1) * sizeof (asection *); - map = bfd_alloc (obfd, amt); + map = bfd_zalloc (obfd, amt); if (map == NULL) return FALSE; @@ -5741,6 +5904,9 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) map->p_flags_valid = 1; map->p_paddr = segment->p_paddr; map->p_paddr_valid = 1; + map->p_align = segment->p_align; + map->p_align_valid = 1; + map->p_vaddr_offset = 0; /* Determine if this segment contains the ELF file header and if it contains the program headers themselves. */ @@ -5760,17 +5926,26 @@ copy_elf_program_header (bfd *ibfd, bfd *obfd) phdr_included = TRUE; } + if (!map->includes_phdrs && !map->includes_filehdr) + /* There is some other padding before the first section. */ + map->p_vaddr_offset = ((first_section ? first_section->lma : 0) + - segment->p_paddr); + if (section_count != 0) { unsigned int isec = 0; - for (section = ibfd->sections; + for (section = first_section; section != NULL; section = section->next) { this_hdr = &(elf_section_data(section)->this_hdr); if (ELF_IS_SECTION_IN_SEGMENT_FILE (this_hdr, segment)) - map->sections[isec++] = section->output_section; + { + map->sections[isec++] = section->output_section; + if (isec == section_count) + break; + } } } @@ -5798,8 +5973,8 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) if (ibfd->xvec == obfd->xvec) { - /* Check if any sections in the input BFD covered by ELF program - header are changed. */ + /* Check to see if any sections in the input BFD + covered by ELF program header have changed. */ Elf_Internal_Phdr *segment; asection *section, *osec; unsigned int i, num_segments; @@ -5815,6 +5990,15 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) i < num_segments; i++, segment++) { + /* PR binutils/3535. The Solaris linker always sets the p_paddr + and p_memsz fields of special segments (DYNAMIC, INTERP) to 0 + which severly confuses things, so always regenerate the segment + map in this case. */ + if (segment->p_paddr == 0 + && segment->p_memsz == 0 + && (segment->p_type == PT_INTERP || segment->p_type == PT_DYNAMIC)) + goto rewrite; + for (section = ibfd->sections; section != NULL; section = section->next) { @@ -5842,7 +6026,7 @@ copy_private_bfd_data (bfd *ibfd, bfd *obfd) } } - /* Check to see if any output section doesn't come from the + /* Check to see if any output section do not come from the input BFD. */ for (section = obfd->sections; section != NULL; section = section->next) @@ -5877,16 +6061,22 @@ _bfd_elf_init_private_section_data (bfd *ibfd, || obfd->xvec->flavour != bfd_target_elf_flavour) return TRUE; - /* FIXME: What if the output ELF section type has been set to - something different? */ - if (elf_section_type (osec) == SHT_NULL) + /* Don't copy the output ELF section type from input if the + output BFD section flags have been set to something different. + elf_fake_sections will set ELF section type based on BFD + section flags. */ + if (elf_section_type (osec) == SHT_NULL + && (osec->flags == isec->flags || !osec->flags)) elf_section_type (osec) = elf_section_type (isec); + /* FIXME: Is this correct for all OS/PROC specific flags? */ + elf_section_flags (osec) |= (elf_section_flags (isec) + & (SHF_MASKOS | SHF_MASKPROC)); + /* Set things up for objcopy and relocatable link. The output SHT_GROUP section will have its elf_next_in_group pointing back to the input group members. Ignore linker created group section. See elfNN_ia64_object_p in elfxx-ia64.c. */ - if (need_group) { if (elf_sec_group (isec) == NULL @@ -5951,6 +6141,8 @@ _bfd_elf_copy_private_section_data (bfd *ibfd, bfd_boolean _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) { + asection *isec; + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; @@ -5966,6 +6158,27 @@ _bfd_elf_copy_private_header_data (bfd *ibfd, bfd *obfd) return FALSE; } + /* _bfd_elf_copy_private_section_data copied over the SHF_GROUP flag + but this might be wrong if we deleted the group section. */ + for (isec = ibfd->sections; isec != NULL; isec = isec->next) + if (elf_section_type (isec) == SHT_GROUP + && isec->output_section == NULL) + { + asection *first = elf_next_in_group (isec); + asection *s = first; + while (s != NULL) + { + if (s->output_section != NULL) + { + elf_section_flags (s->output_section) &= ~SHF_GROUP; + elf_group_name (s->output_section) = NULL; + } + s = elf_next_in_group (s); + if (s == first) + break; + } + } + return TRUE; } @@ -6238,6 +6451,10 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), type = STT_FUNC; else if ((flags & BSF_OBJECT) != 0) type = STT_OBJECT; + else if ((flags & BSF_RELC) != 0) + type = STT_RELC; + else if ((flags & BSF_SRELC) != 0) + type = STT_SRELC; else type = STT_NOTYPE; @@ -7036,13 +7253,31 @@ _bfd_elf_find_inliner_info (bfd *abfd, } int -_bfd_elf_sizeof_headers (bfd *abfd, bfd_boolean reloc) +_bfd_elf_sizeof_headers (bfd *abfd, struct bfd_link_info *info) { - int ret; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + int ret = bed->s->sizeof_ehdr; + + if (!info->relocatable) + { + bfd_size_type phdr_size = elf_tdata (abfd)->program_header_size; + + if (phdr_size == (bfd_size_type) -1) + { + struct elf_segment_map *m; + + phdr_size = 0; + for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) + phdr_size += bed->s->sizeof_phdr; + + if (phdr_size == 0) + phdr_size = get_program_header_size (abfd, info); + } + + elf_tdata (abfd)->program_header_size = phdr_size; + ret += phdr_size; + } - ret = get_elf_backend_data (abfd)->s->sizeof_ehdr; - if (! reloc) - ret += get_program_header_size (abfd); return ret; } @@ -7178,7 +7413,7 @@ _bfd_elf_close_and_cleanup (bfd *abfd) { if (bfd_get_format (abfd) == bfd_object) { - if (elf_shstrtab (abfd) != NULL) + if (elf_tdata (abfd) != NULL && elf_shstrtab (abfd) != NULL) _bfd_elf_strtab_free (elf_shstrtab (abfd)); _bfd_dwarf2_cleanup_debug_info (abfd); } @@ -7232,13 +7467,12 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect) if (bfd_get_section_by_name (abfd, name) != NULL) return TRUE; - sect2 = bfd_make_section (abfd, name); + sect2 = bfd_make_section_with_flags (abfd, name, sect->flags); if (sect2 == NULL) return FALSE; sect2->size = sect->size; sect2->filepos = sect->filepos; - sect2->flags = sect->flags; sect2->alignment_power = sect->alignment_power; return TRUE; } @@ -7270,12 +7504,12 @@ _bfd_elfcore_make_pseudosection (bfd *abfd, return FALSE; memcpy (threaded_name, buf, len); - sect = bfd_make_section_anyway (abfd, threaded_name); + sect = bfd_make_section_anyway_with_flags (abfd, threaded_name, + SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = size; sect->filepos = filepos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; return elfcore_maybe_make_sect (abfd, name, sect); @@ -7554,7 +7788,7 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) return FALSE; memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; @@ -7569,7 +7803,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_reg); #endif - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; if (!elfcore_maybe_make_sect (abfd, ".reg", sect)) @@ -7584,7 +7817,7 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) return FALSE; memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; @@ -7599,7 +7832,6 @@ elfcore_grok_lwpstatus (bfd *abfd, Elf_Internal_Note *note) sect->filepos = note->descpos + offsetof (lwpstatus_t, pr_fpreg); #endif - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; return elfcore_maybe_make_sect (abfd, ".reg2", sect); @@ -7640,7 +7872,7 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; @@ -7648,7 +7880,6 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) sect->filepos = (note->descpos + offsetof (struct win32_pstatus, data.thread_info.thread_context)); - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; if (pstatus.data.thread_info.is_active_thread) @@ -7668,14 +7899,13 @@ elfcore_grok_win32pstatus (bfd *abfd, Elf_Internal_Note *note) memcpy (name, buf, len); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; break; @@ -7745,13 +7975,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) case NT_AUXV: { - asection *sect = bfd_make_section_anyway (abfd, ".auxv"); + asection *sect = bfd_make_section_anyway_with_flags (abfd, ".auxv", + SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 1 + bfd_get_arch_size (abfd) / 32; return TRUE; @@ -7776,7 +8006,6 @@ elfcore_netbsd_get_lwpid (Elf_Internal_Note *note, int *lwpidp) static bfd_boolean elfcore_grok_netbsd_procinfo (bfd *abfd, Elf_Internal_Note *note) { - /* Signal number at offset 0x08. */ elf_tdata (abfd)->core_signal = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + 0x08); @@ -7804,9 +8033,9 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) if (note->type == NT_NETBSDCORE_PROCINFO) { /* NetBSD-specific core "procinfo". Note that we expect to - find this note before any of the others, which is fine, - since the kernel writes this note out first when it - creates a core file. */ + find this note before any of the others, which is fine, + since the kernel writes this note out first when it + creates a core file. */ return elfcore_grok_netbsd_procinfo (abfd, note); } @@ -7822,44 +8051,44 @@ elfcore_grok_netbsd_note (bfd *abfd, Elf_Internal_Note *note) switch (bfd_get_arch (abfd)) { - /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and - PT_GETFPREGS == mach+2. */ + /* On the Alpha, SPARC (32-bit and 64-bit), PT_GETREGS == mach+0 and + PT_GETFPREGS == mach+2. */ case bfd_arch_alpha: case bfd_arch_sparc: switch (note->type) - { - case NT_NETBSDCORE_FIRSTMACH+0: - return elfcore_make_note_pseudosection (abfd, ".reg", note); + { + case NT_NETBSDCORE_FIRSTMACH+0: + return elfcore_make_note_pseudosection (abfd, ".reg", note); - case NT_NETBSDCORE_FIRSTMACH+2: - return elfcore_make_note_pseudosection (abfd, ".reg2", note); + case NT_NETBSDCORE_FIRSTMACH+2: + return elfcore_make_note_pseudosection (abfd, ".reg2", note); - default: - return TRUE; - } + default: + return TRUE; + } - /* On all other arch's, PT_GETREGS == mach+1 and - PT_GETFPREGS == mach+3. */ + /* On all other arch's, PT_GETREGS == mach+1 and + PT_GETFPREGS == mach+3. */ default: switch (note->type) - { - case NT_NETBSDCORE_FIRSTMACH+1: - return elfcore_make_note_pseudosection (abfd, ".reg", note); + { + case NT_NETBSDCORE_FIRSTMACH+1: + return elfcore_make_note_pseudosection (abfd, ".reg", note); - case NT_NETBSDCORE_FIRSTMACH+3: - return elfcore_make_note_pseudosection (abfd, ".reg2", note); + case NT_NETBSDCORE_FIRSTMACH+3: + return elfcore_make_note_pseudosection (abfd, ".reg2", note); - default: - return TRUE; - } + default: + return TRUE; + } } /* NOTREACHED */ } static bfd_boolean -elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) +elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, long *tid) { void *ddata = note->descdata; char buf[100]; @@ -7891,20 +8120,19 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) elf_tdata (abfd)->core_lwpid = *tid; /* Make a ".qnx_core_status/%d" section. */ - sprintf (buf, ".qnx_core_status/%ld", (long) *tid); + sprintf (buf, ".qnx_core_status/%ld", *tid); name = bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) return FALSE; strcpy (name, buf); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; return (elfcore_maybe_make_sect (abfd, ".qnx_core_status", sect)); @@ -7913,7 +8141,7 @@ elfcore_grok_nto_status (bfd *abfd, Elf_Internal_Note *note, pid_t *tid) static bfd_boolean elfcore_grok_nto_regs (bfd *abfd, Elf_Internal_Note *note, - pid_t tid, + long tid, char *base) { char buf[100]; @@ -7921,20 +8149,19 @@ elfcore_grok_nto_regs (bfd *abfd, asection *sect; /* Make a "(base)/%d" section. */ - sprintf (buf, "%s/%ld", base, (long) tid); + sprintf (buf, "%s/%ld", base, tid); name = bfd_alloc (abfd, strlen (buf) + 1); if (name == NULL) return FALSE; strcpy (name, buf); - sect = bfd_make_section_anyway (abfd, name); + sect = bfd_make_section_anyway_with_flags (abfd, name, SEC_HAS_CONTENTS); if (sect == NULL) return FALSE; sect->size = note->descsz; sect->filepos = note->descpos; - sect->flags = SEC_HAS_CONTENTS; sect->alignment_power = 2; /* This is the current thread. */ @@ -7955,7 +8182,7 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note) /* Every GREG section has a STATUS section before it. Store the tid from the previous call to pass down to the next gregs function. */ - static pid_t tid = 1; + static long tid = 1; switch (note->type) { @@ -7975,45 +8202,42 @@ elfcore_grok_nto_note (bfd *abfd, Elf_Internal_Note *note) /* Function: elfcore_write_note Inputs: - buffer to hold note + buffer to hold note, and current size of buffer name of note type of note data for note size of data for note + Writes note to end of buffer. ELF64 notes are written exactly as + for ELF32, despite the current (as of 2006) ELF gabi specifying + that they ought to have 8-byte namesz and descsz field, and have + 8-byte alignment. Other writers, eg. Linux kernel, do the same. + Return: - End of buffer containing note. */ + Pointer to realloc'd buffer, *BUFSIZ updated. */ char * -elfcore_write_note (bfd *abfd, +elfcore_write_note (bfd *abfd, char *buf, - int *bufsiz, + int *bufsiz, const char *name, - int type, + int type, const void *input, - int size) + int size) { Elf_External_Note *xnp; size_t namesz; - size_t pad; size_t newspace; - char *p, *dest; + char *dest; namesz = 0; - pad = 0; if (name != NULL) - { - const struct elf_backend_data *bed; - - namesz = strlen (name) + 1; - bed = get_elf_backend_data (abfd); - pad = -namesz & ((1 << bed->s->log_file_align) - 1); - } + namesz = strlen (name) + 1; - newspace = 12 + namesz + pad + size; + newspace = 12 + ((namesz + 3) & -4) + ((size + 3) & -4); - p = realloc (buf, *bufsiz + newspace); - dest = p + *bufsiz; + buf = realloc (buf, *bufsiz + newspace); + dest = buf + *bufsiz; *bufsiz += newspace; xnp = (Elf_External_Note *) dest; H_PUT_32 (abfd, namesz, xnp->namesz); @@ -8024,14 +8248,20 @@ elfcore_write_note (bfd *abfd, { memcpy (dest, name, namesz); dest += namesz; - while (pad != 0) + while (namesz & 3) { *dest++ = '\0'; - --pad; + ++namesz; } } memcpy (dest, input, size); - return p; + dest += size; + while (size & 3) + { + *dest++ = '\0'; + ++size; + } + return buf; } #if defined (HAVE_PRPSINFO_T) || defined (HAVE_PSINFO_T) @@ -8042,22 +8272,52 @@ elfcore_write_prpsinfo (bfd *abfd, const char *fname, const char *psargs) { - int note_type; - char *note_name = "CORE"; + const char *note_name = "CORE"; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + + if (bed->elf_backend_write_core_note != NULL) + { + char *ret; + ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz, + NT_PRPSINFO, fname, psargs); + if (ret != NULL) + return ret; + } + +#if defined (HAVE_PRPSINFO32_T) || defined (HAVE_PSINFO32_T) + if (bed->s->elfclass == ELFCLASS32) + { +#if defined (HAVE_PSINFO32_T) + psinfo32_t data; + int note_type = NT_PSINFO; +#else + prpsinfo32_t data; + int note_type = NT_PRPSINFO; +#endif + memset (&data, 0, sizeof (data)); + strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); + strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); + return elfcore_write_note (abfd, buf, bufsiz, + note_name, note_type, &data, sizeof (data)); + } + else +#endif + { #if defined (HAVE_PSINFO_T) - psinfo_t data; - note_type = NT_PSINFO; + psinfo_t data; + int note_type = NT_PSINFO; #else - prpsinfo_t data; - note_type = NT_PRPSINFO; + prpsinfo_t data; + int note_type = NT_PRPSINFO; #endif - memset (&data, 0, sizeof (data)); - strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); - strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); - return elfcore_write_note (abfd, buf, bufsiz, - note_name, note_type, &data, sizeof (data)); + memset (&data, 0, sizeof (data)); + strncpy (data.pr_fname, fname, sizeof (data.pr_fname)); + strncpy (data.pr_psargs, psargs, sizeof (data.pr_psargs)); + return elfcore_write_note (abfd, buf, bufsiz, + note_name, note_type, &data, sizeof (data)); + } } #endif /* PSINFO_T or PRPSINFO_T */ @@ -8070,15 +8330,43 @@ elfcore_write_prstatus (bfd *abfd, int cursig, const void *gregs) { - prstatus_t prstat; - char *note_name = "CORE"; + const char *note_name = "CORE"; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); - memset (&prstat, 0, sizeof (prstat)); - prstat.pr_pid = pid; - prstat.pr_cursig = cursig; - memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); - return elfcore_write_note (abfd, buf, bufsiz, - note_name, NT_PRSTATUS, &prstat, sizeof (prstat)); + if (bed->elf_backend_write_core_note != NULL) + { + char *ret; + ret = (*bed->elf_backend_write_core_note) (abfd, buf, bufsiz, + NT_PRSTATUS, + pid, cursig, gregs); + if (ret != NULL) + return ret; + } + +#if defined (HAVE_PRSTATUS32_T) + if (bed->s->elfclass == ELFCLASS32) + { + prstatus32_t prstat; + + memset (&prstat, 0, sizeof (prstat)); + prstat.pr_pid = pid; + prstat.pr_cursig = cursig; + memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); + return elfcore_write_note (abfd, buf, bufsiz, note_name, + NT_PRSTATUS, &prstat, sizeof (prstat)); + } + else +#endif + { + prstatus_t prstat; + + memset (&prstat, 0, sizeof (prstat)); + prstat.pr_pid = pid; + prstat.pr_cursig = cursig; + memcpy (&prstat.pr_reg, gregs, sizeof (prstat.pr_reg)); + return elfcore_write_note (abfd, buf, bufsiz, note_name, + NT_PRSTATUS, &prstat, sizeof (prstat)); + } } #endif /* HAVE_PRSTATUS_T */ @@ -8092,7 +8380,7 @@ elfcore_write_lwpstatus (bfd *abfd, const void *gregs) { lwpstatus_t lwpstat; - char *note_name = "CORE"; + const char *note_name = "CORE"; memset (&lwpstat, 0, sizeof (lwpstat)); lwpstat.pr_lwpid = pid >> 16; @@ -8122,14 +8410,31 @@ elfcore_write_pstatus (bfd *abfd, int cursig ATTRIBUTE_UNUSED, const void *gregs ATTRIBUTE_UNUSED) { - pstatus_t pstat; - char *note_name = "CORE"; + const char *note_name = "CORE"; +#if defined (HAVE_PSTATUS32_T) + const struct elf_backend_data *bed = get_elf_backend_data (abfd); - memset (&pstat, 0, sizeof (pstat)); - pstat.pr_pid = pid & 0xffff; - buf = elfcore_write_note (abfd, buf, bufsiz, note_name, - NT_PSTATUS, &pstat, sizeof (pstat)); - return buf; + if (bed->s->elfclass == ELFCLASS32) + { + pstatus32_t pstat; + + memset (&pstat, 0, sizeof (pstat)); + pstat.pr_pid = pid & 0xffff; + buf = elfcore_write_note (abfd, buf, bufsiz, note_name, + NT_PSTATUS, &pstat, sizeof (pstat)); + return buf; + } + else +#endif + { + pstatus_t pstat; + + memset (&pstat, 0, sizeof (pstat)); + pstat.pr_pid = pid & 0xffff; + buf = elfcore_write_note (abfd, buf, bufsiz, note_name, + NT_PSTATUS, &pstat, sizeof (pstat)); + return buf; + } } #endif /* HAVE_PSTATUS_T */ @@ -8140,7 +8445,7 @@ elfcore_write_prfpreg (bfd *abfd, const void *fpregs, int size) { - char *note_name = "CORE"; + const char *note_name = "CORE"; return elfcore_write_note (abfd, buf, bufsiz, note_name, NT_FPREGSET, fpregs, size); } @@ -8196,21 +8501,21 @@ elfcore_read_notes (bfd *abfd, file_ptr offset, bfd_size_type size) in.descdata = in.namedata + BFD_ALIGN (in.namesz, 4); in.descpos = offset + (in.descdata - buf); - if (strncmp (in.namedata, "NetBSD-CORE", 11) == 0) - { - if (! elfcore_grok_netbsd_note (abfd, &in)) - goto error; - } - else if (strncmp (in.namedata, "QNX", 3) == 0) + if (CONST_STRNEQ (in.namedata, "NetBSD-CORE")) + { + if (! elfcore_grok_netbsd_note (abfd, &in)) + goto error; + } + else if (CONST_STRNEQ (in.namedata, "QNX")) { if (! elfcore_grok_nto_note (abfd, &in)) goto error; } else - { - if (! elfcore_grok_note (abfd, &in)) - goto error; - } + { + if (! elfcore_grok_note (abfd, &in)) + goto error; + } p = in.descdata + BFD_ALIGN (in.descsz, 4); } @@ -8516,39 +8821,41 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, return n; } -/* Sort symbol by binding and section. We want to put definitions - sorted by section at the beginning. */ - -static int -elf_sort_elf_symbol (const void *arg1, const void *arg2) +struct elf_symbuf_symbol { - const Elf_Internal_Sym *s1; - const Elf_Internal_Sym *s2; - int shndx; - - /* Make sure that undefined symbols are at the end. */ - s1 = (const Elf_Internal_Sym *) arg1; - if (s1->st_shndx == SHN_UNDEF) - return 1; - s2 = (const Elf_Internal_Sym *) arg2; - if (s2->st_shndx == SHN_UNDEF) - return -1; - - /* Sorted by section index. */ - shndx = s1->st_shndx - s2->st_shndx; - if (shndx != 0) - return shndx; + unsigned long st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* Visibilty, and target specific */ +}; - /* Sorted by binding. */ - return ELF_ST_BIND (s1->st_info) - ELF_ST_BIND (s2->st_info); -} +struct elf_symbuf_head +{ + struct elf_symbuf_symbol *ssym; + bfd_size_type count; + unsigned int st_shndx; +}; struct elf_symbol { - Elf_Internal_Sym *sym; + union + { + Elf_Internal_Sym *isym; + struct elf_symbuf_symbol *ssym; + } u; const char *name; }; +/* Sort references to symbols by ascending section number. */ + +static int +elf_sort_elf_symbol (const void *arg1, const void *arg2) +{ + const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1; + const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2; + + return s1->st_shndx - s2->st_shndx; +} + static int elf_sym_name_compare (const void *arg1, const void *arg2) { @@ -8557,20 +8864,79 @@ elf_sym_name_compare (const void *arg1, const void *arg2) return strcmp (s1->name, s2->name); } +static struct elf_symbuf_head * +elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf) +{ + Elf_Internal_Sym **ind, **indbufend, **indbuf + = bfd_malloc2 (symcount, sizeof (*indbuf)); + struct elf_symbuf_symbol *ssym; + struct elf_symbuf_head *ssymbuf, *ssymhead; + bfd_size_type i, shndx_count; + + if (indbuf == NULL) + return NULL; + + for (ind = indbuf, i = 0; i < symcount; i++) + if (isymbuf[i].st_shndx != SHN_UNDEF) + *ind++ = &isymbuf[i]; + indbufend = ind; + + qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *), + elf_sort_elf_symbol); + + shndx_count = 0; + if (indbufend > indbuf) + for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++) + if (ind[0]->st_shndx != ind[1]->st_shndx) + shndx_count++; + + ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf) + + (indbufend - indbuf) * sizeof (*ssymbuf)); + if (ssymbuf == NULL) + { + free (indbuf); + return NULL; + } + + ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count); + ssymbuf->ssym = NULL; + ssymbuf->count = shndx_count; + ssymbuf->st_shndx = 0; + for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++) + { + if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx) + { + ssymhead++; + ssymhead->ssym = ssym; + ssymhead->count = 0; + ssymhead->st_shndx = (*ind)->st_shndx; + } + ssym->st_name = (*ind)->st_name; + ssym->st_info = (*ind)->st_info; + ssym->st_other = (*ind)->st_other; + ssymhead->count++; + } + BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count); + + free (indbuf); + return ssymbuf; +} + /* Check if 2 sections define the same set of local and global symbols. */ bfd_boolean -bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2) +bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, + struct bfd_link_info *info) { bfd *bfd1, *bfd2; const struct elf_backend_data *bed1, *bed2; Elf_Internal_Shdr *hdr1, *hdr2; bfd_size_type symcount1, symcount2; Elf_Internal_Sym *isymbuf1, *isymbuf2; - Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym; - Elf_Internal_Sym *isymend; - struct elf_symbol *symp, *symtable1 = NULL, *symtable2 = NULL; + struct elf_symbuf_head *ssymbuf1, *ssymbuf2; + Elf_Internal_Sym *isym, *isymend; + struct elf_symbol *symtable1 = NULL, *symtable2 = NULL; bfd_size_type count1, count2, i; int shndx1, shndx2; bfd_boolean result; @@ -8580,10 +8946,8 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2) /* If both are .gnu.linkonce sections, they have to have the same section name. */ - if (strncmp (sec1->name, ".gnu.linkonce", - sizeof ".gnu.linkonce" - 1) == 0 - && strncmp (sec2->name, ".gnu.linkonce", - sizeof ".gnu.linkonce" - 1) == 0) + if (CONST_STRNEQ (sec1->name, ".gnu.linkonce") + && CONST_STRNEQ (sec2->name, ".gnu.linkonce")) return strcmp (sec1->name + sizeof ".gnu.linkonce", sec2->name + sizeof ".gnu.linkonce") == 0; @@ -8619,84 +8983,155 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2) if (symcount1 == 0 || symcount2 == 0) return FALSE; - isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, - NULL, NULL, NULL); - isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, - NULL, NULL, NULL); - result = FALSE; - if (isymbuf1 == NULL || isymbuf2 == NULL) - goto done; + isymbuf1 = NULL; + isymbuf2 = NULL; + ssymbuf1 = elf_tdata (bfd1)->symbuf; + ssymbuf2 = elf_tdata (bfd2)->symbuf; - /* Sort symbols by binding and section. Global definitions are at - the beginning. */ - qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym), - elf_sort_elf_symbol); - qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym), - elf_sort_elf_symbol); + if (ssymbuf1 == NULL) + { + isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, + NULL, NULL, NULL); + if (isymbuf1 == NULL) + goto done; - /* Count definitions in the section. */ - count1 = 0; - for (isym = isymbuf1, isymend = isym + symcount1; - isym < isymend; isym++) + if (!info->reduce_memory_overheads) + elf_tdata (bfd1)->symbuf = ssymbuf1 + = elf_create_symbuf (symcount1, isymbuf1); + } + + if (ssymbuf1 == NULL || ssymbuf2 == NULL) { - if (isym->st_shndx == (unsigned int) shndx1) - { - if (count1 == 0) - isymstart1 = isym; - count1++; - } + isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, + NULL, NULL, NULL); + if (isymbuf2 == NULL) + goto done; - if (count1 && isym->st_shndx != (unsigned int) shndx1) - break; + if (ssymbuf1 != NULL && !info->reduce_memory_overheads) + elf_tdata (bfd2)->symbuf = ssymbuf2 + = elf_create_symbuf (symcount2, isymbuf2); } - count2 = 0; - for (isym = isymbuf2, isymend = isym + symcount2; - isym < isymend; isym++) + if (ssymbuf1 != NULL && ssymbuf2 != NULL) { - if (isym->st_shndx == (unsigned int) shndx2) + /* Optimized faster version. */ + bfd_size_type lo, hi, mid; + struct elf_symbol *symp; + struct elf_symbuf_symbol *ssym, *ssymend; + + lo = 0; + hi = ssymbuf1->count; + ssymbuf1++; + count1 = 0; + while (lo < hi) { - if (count2 == 0) - isymstart2 = isym; - count2++; + mid = (lo + hi) / 2; + if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx) + hi = mid; + else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx) + lo = mid + 1; + else + { + count1 = ssymbuf1[mid].count; + ssymbuf1 += mid; + break; + } } - if (count2 && isym->st_shndx != (unsigned int) shndx2) - break; + lo = 0; + hi = ssymbuf2->count; + ssymbuf2++; + count2 = 0; + while (lo < hi) + { + mid = (lo + hi) / 2; + if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx) + hi = mid; + else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx) + lo = mid + 1; + else + { + count2 = ssymbuf2[mid].count; + ssymbuf2 += mid; + break; + } + } + + if (count1 == 0 || count2 == 0 || count1 != count2) + goto done; + + symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol)); + symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol)); + if (symtable1 == NULL || symtable2 == NULL) + goto done; + + symp = symtable1; + for (ssym = ssymbuf1->ssym, ssymend = ssym + count1; + ssym < ssymend; ssym++, symp++) + { + symp->u.ssym = ssym; + symp->name = bfd_elf_string_from_elf_section (bfd1, + hdr1->sh_link, + ssym->st_name); + } + + symp = symtable2; + for (ssym = ssymbuf2->ssym, ssymend = ssym + count2; + ssym < ssymend; ssym++, symp++) + { + symp->u.ssym = ssym; + symp->name = bfd_elf_string_from_elf_section (bfd2, + hdr2->sh_link, + ssym->st_name); + } + + /* Sort symbol by name. */ + qsort (symtable1, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + qsort (symtable2, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + + for (i = 0; i < count1; i++) + /* Two symbols must have the same binding, type and name. */ + if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info + || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other + || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) + goto done; + + result = TRUE; + goto done; } - if (count1 == 0 || count2 == 0 || count1 != count2) + symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol)); + symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol)); + if (symtable1 == NULL || symtable2 == NULL) goto done; - symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol)); - symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol)); + /* Count definitions in the section. */ + count1 = 0; + for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++) + if (isym->st_shndx == (unsigned int) shndx1) + symtable1[count1++].u.isym = isym; - if (symtable1 == NULL || symtable2 == NULL) + count2 = 0; + for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++) + if (isym->st_shndx == (unsigned int) shndx2) + symtable2[count2++].u.isym = isym; + + if (count1 == 0 || count2 == 0 || count1 != count2) goto done; - symp = symtable1; - for (isym = isymstart1, isymend = isym + count1; - isym < isymend; isym++) - { - symp->sym = isym; - symp->name = bfd_elf_string_from_elf_section (bfd1, - hdr1->sh_link, - isym->st_name); - symp++; - } - - symp = symtable2; - for (isym = isymstart2, isymend = isym + count1; - isym < isymend; isym++) - { - symp->sym = isym; - symp->name = bfd_elf_string_from_elf_section (bfd2, - hdr2->sh_link, - isym->st_name); - symp++; - } - + for (i = 0; i < count1; i++) + symtable1[i].name + = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, + symtable1[i].u.isym->st_name); + + for (i = 0; i < count2; i++) + symtable2[i].name + = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, + symtable2[i].u.isym->st_name); + /* Sort symbol by name. */ qsort (symtable1, count1, sizeof (struct elf_symbol), elf_sym_name_compare); @@ -8705,8 +9140,8 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2) for (i = 0; i < count1; i++) /* Two symbols must have the same binding, type and name. */ - if (symtable1 [i].sym->st_info != symtable2 [i].sym->st_info - || symtable1 [i].sym->st_other != symtable2 [i].sym->st_other + if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info + || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) goto done; @@ -8728,8 +9163,7 @@ done: /* It is only used by x86-64 so far. */ asection _bfd_elf_large_com_section = BFD_FAKE_SECTION (_bfd_elf_large_com_section, - SEC_IS_COMMON, NULL, NULL, "LARGE_COMMON", - 0); + SEC_IS_COMMON, NULL, "LARGE_COMMON", 0); /* Return TRUE if 2 section types are compatible. */ @@ -8745,3 +9179,25 @@ _bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec, return elf_section_type (asec) == elf_section_type (bsec); } + +void +_bfd_elf_set_osabi (bfd * abfd, + struct bfd_link_info * link_info ATTRIBUTE_UNUSED) +{ + Elf_Internal_Ehdr * i_ehdrp; /* ELF file header, internal form. */ + + i_ehdrp = elf_elfheader (abfd); + + i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; +} + + +/* Return TRUE for ELF symbol types that represent functions. + This is the default version of this function, which is sufficient for + most targets. It returns true if TYPE is STT_FUNC. */ + +bfd_boolean +_bfd_elf_is_function_type (unsigned int type) +{ + return (type == STT_FUNC); +} |