X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf.c;h=69830ce0b3a2e567dcb052ba19a011d91af67c93;hb=7634c4e679156fc6a93ccb8b33898f5cf41eb233;hp=a1f857a900b44c9bf18617db43a9738f9e100dcd;hpb=6f2750feaf2827ef8a1a0a5b2f90c1e9a6cabbd1;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf.c b/bfd/elf.c index a1f857a900..69830ce0b3 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -42,7 +42,7 @@ SECTION #include "elf-bfd.h" #include "libiberty.h" #include "safe-ctype.h" -#include "elf-linux-psinfo.h" +#include "elf-linux-core.h" #ifdef CORE_HEADER #include CORE_HEADER @@ -970,9 +970,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, { flags |= SEC_MERGE; newsect->entsize = hdr->sh_entsize; - if ((hdr->sh_flags & SHF_STRINGS) != 0) - flags |= SEC_STRINGS; } + if ((hdr->sh_flags & SHF_STRINGS) != 0) + flags |= SEC_STRINGS; if (hdr->sh_flags & SHF_GROUP) if (!setup_group (abfd, hdr, newsect)) return FALSE; @@ -1175,7 +1175,8 @@ _bfd_elf_make_section_from_shdr (bfd *abfd, return TRUE; } -const char *const bfd_elf_section_type_names[] = { +const char *const bfd_elf_section_type_names[] = +{ "SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB", "SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", "SHT_NOBITS", "SHT_REL", "SHT_SHLIB", "SHT_DYNSYM", @@ -1212,14 +1213,62 @@ bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, return bfd_reloc_continue; } +/* Returns TRUE if section A matches section B. + Names, addresses and links may be different, but everything else + should be the same. */ + +static bfd_boolean +section_match (Elf_Internal_Shdr * a, Elf_Internal_Shdr * b) +{ + return + a->sh_type == b->sh_type + && a->sh_flags == b->sh_flags + && a->sh_addralign == b->sh_addralign + && a->sh_size == b->sh_size + && a->sh_entsize == b->sh_entsize + /* FIXME: Check sh_addr ? */ + ; +} + +/* Find a section in OBFD that has the same characteristics + as IHEADER. Return the index of this section or SHN_UNDEF if + none can be found. Check's section HINT first, as this is likely + to be the correct section. */ + +static unsigned int +find_link (bfd * obfd, Elf_Internal_Shdr * iheader, unsigned int hint) +{ + Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd); + unsigned int i; + + if (section_match (oheaders[hint], iheader)) + return hint; + + for (i = 1; i < elf_numsections (obfd); i++) + { + Elf_Internal_Shdr * oheader = oheaders[i]; + + if (section_match (oheader, iheader)) + /* FIXME: Do we care if there is a potential for + multiple matches ? */ + return i; + } + + return SHN_UNDEF; +} + /* Copy the program header and other data from one object module to another. */ bfd_boolean _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) { + Elf_Internal_Shdr ** iheaders = elf_elfsections (ibfd); + Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd); + unsigned int i; + if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour - || bfd_get_flavour (obfd) != bfd_target_elf_flavour) + || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; if (!elf_flags_init (obfd)) @@ -1237,59 +1286,128 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd) /* Copy object attributes. */ _bfd_elf_copy_obj_attributes (ibfd, obfd); - /* This is an feature for objcopy --only-keep-debug: When a section's type - is changed to NOBITS, we preserve the sh_link and sh_info fields so that - they can be matched up with the original. */ - Elf_Internal_Shdr ** iheaders = elf_elfsections (ibfd); - Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd); + if (iheaders == NULL || oheaders == NULL) + return TRUE; - if (iheaders != NULL && oheaders != NULL) + /* Possibly copy the sh_info and sh_link fields. */ + for (i = 1; i < elf_numsections (obfd); i++) { - unsigned int i; - - for (i = 0; i < elf_numsections (obfd); i++) - { - unsigned int j; - Elf_Internal_Shdr * oheader = oheaders[i]; + unsigned int j; + Elf_Internal_Shdr * oheader = oheaders[i]; - if (oheader == NULL - || oheader->sh_type != SHT_NOBITS - || oheader->sh_size == 0 - || (oheader->sh_info != 0 && oheader->sh_link != 0)) - continue; + if (oheader == NULL + || (oheader->sh_type != SHT_NOBITS + && oheader->sh_type < SHT_LOOS) + || oheader->sh_size == 0 + || (oheader->sh_info != 0 && oheader->sh_link != 0)) + continue; - /* Scan for the matching section in the input bfd. - FIXME: We could use something better than a linear scan here. - Unfortunately we cannot compare names as the output string table - is empty, so instead we check size, address and type. */ - for (j = 0; j < elf_numsections (ibfd); j++) + /* Scan for the matching section in the input bfd. + FIXME: We could use something better than a linear scan here. + Unfortunately we cannot compare names as the output string table + is empty, so instead we check size, address and type. */ + for (j = 1; j < elf_numsections (ibfd); j++) + { + Elf_Internal_Shdr * iheader = iheaders[j]; + + /* Since --only-keep-debug turns all non-debug sections into + SHT_NOBITS sections, the output SHT_NOBITS type matches any + input type. */ + if ((oheader->sh_type == SHT_NOBITS + || iheader->sh_type == oheader->sh_type) + && iheader->sh_flags == oheader->sh_flags + && iheader->sh_addralign == oheader->sh_addralign + && iheader->sh_entsize == oheader->sh_entsize + && iheader->sh_size == oheader->sh_size + && iheader->sh_addr == oheader->sh_addr + && (iheader->sh_info != oheader->sh_info + || iheader->sh_link != oheader->sh_link)) { - Elf_Internal_Shdr * iheader = iheaders[j]; - - /* Since --only-keep-debug turns all non-debug sections - into SHT_NOBITS sections, the output SHT_NOBITS type - matches any input type. */ - if ((oheader->sh_type == SHT_NOBITS - || iheader->sh_type == oheader->sh_type) - && iheader->sh_flags == oheader->sh_flags - && iheader->sh_addralign == oheader->sh_addralign - && iheader->sh_entsize == oheader->sh_entsize - && iheader->sh_size == oheader->sh_size - && iheader->sh_addr == oheader->sh_addr - && (iheader->sh_info != oheader->sh_info - || iheader->sh_link != oheader->sh_link)) + /* PR 19938: Attempt to preserve the sh_link and sh_info fields + of OS and Processor specific sections. We try harder for + these sections, because this is not just about matching + stripped binaries to their originals. */ + if (oheader->sh_type >= SHT_LOOS) { - /* Note: Strictly speaking these assignments are wrong. + const struct elf_backend_data *bed = get_elf_backend_data (obfd); + bfd_boolean changed = FALSE; + unsigned int sh_link; + + /* Allow the target a chance to decide how these fields should + be set. */ + if (bed->elf_backend_set_special_section_info_and_link != NULL + && bed->elf_backend_set_special_section_info_and_link + (ibfd, obfd, iheader, oheader)) + break; + + /* We have iheader which matches oheader, but which has + non-zero sh_info and/or sh_link fields. Attempt to + follow those links and find the section in the output + bfd which corresponds to the linked section in the input + bfd. */ + if (iheader->sh_link != SHN_UNDEF) + { + sh_link = find_link (obfd, + iheaders[iheader->sh_link], + iheader->sh_link); + if (sh_link != SHN_UNDEF) + { + oheader->sh_link = sh_link; + changed = TRUE; + } + else + /* FIXME: Should we install iheader->sh_link + if we could not find a match ? */ + (* _bfd_error_handler) + (_("%B: Failed to find link section for section %d"), + obfd, i); + } + + if (iheader->sh_info) + { + /* The sh_info field can hold arbitrary information, + but if the SHF_LINK_INFO flag is set then it + should be interpreted as a section index. */ + if (iheader->sh_flags & SHF_INFO_LINK) + sh_link = find_link (obfd, + iheaders[iheader->sh_info], + iheader->sh_info); + else + /* No idea what it means - just copy it. */ + sh_link = iheader->sh_info; + + if (sh_link != SHN_UNDEF) + { + oheader->sh_info = sh_link; + changed = TRUE; + } + else + (* _bfd_error_handler) + (_("%B: Failed to find info section for section %d"), + obfd, i); + } + + if (changed) + break; + } + else + { + /* This is an feature for objcopy --only-keep-debug: + When a section's type is changed to NOBITS, we preserve + the sh_link and sh_info fields so that they can be + matched up with the original. + + Note: Strictly speaking these assignments are wrong. The sh_link and sh_info fields should point to the relevent sections in the output BFD, which may not be in - the same location as they were in the input BFD. But the - whole point of this action is to preserve the original - values of the sh_link and sh_info fields, so that they - can be matched up with the section headers in the - original file. So strictly speaking we may be creating - an invalid ELF file, but it is only for a file that just - contains debug info and only for sections without any - contents. */ + the same location as they were in the input BFD. But + the whole point of this action is to preserve the + original values of the sh_link and sh_info fields, so + that they can be matched up with the section headers in + the original file. So strictly speaking we may be + creating an invalid ELF file, but it is only for a file + that just contains debug info and only for sections + without any contents. */ if (oheader->sh_link == 0) oheader->sh_link = iheader->sh_link; if (oheader->sh_info == 0) @@ -3099,9 +3217,9 @@ elf_fake_sections (bfd *abfd, asection *asect, void *fsarg) { this_hdr->sh_flags |= SHF_MERGE; this_hdr->sh_entsize = asect->entsize; - if ((asect->flags & SEC_STRINGS) != 0) - this_hdr->sh_flags |= SHF_STRINGS; } + if ((asect->flags & SEC_STRINGS) != 0) + this_hdr->sh_flags |= SHF_STRINGS; if ((asect->flags & SEC_GROUP) == 0 && elf_group_name (asect) != NULL) this_hdr->sh_flags |= SHF_GROUP; if ((asect->flags & SEC_THREAD_LOCAL) != 0) @@ -3355,6 +3473,8 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) /* SHT_GROUP sections are in relocatable files only. */ if (link_info == NULL || bfd_link_relocatable (link_info)) { + bfd_size_type reloc_count = 0; + /* Put SHT_GROUP sections first. */ for (sec = abfd->sections; sec != NULL; sec = sec->next) { @@ -3371,7 +3491,14 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) else d->this_idx = section_number++; } + + /* Count relocations. */ + reloc_count += sec->reloc_count; } + + /* Clear HAS_RELOC if there are no relocations. */ + if (reloc_count == 0) + abfd->flags &= ~HAS_RELOC; } for (sec = abfd->sections; sec; sec = sec->next) @@ -3910,7 +4037,7 @@ _bfd_elf_compute_section_file_positions (bfd *abfd, shstrtab_hdr = &elf_tdata (abfd)->shstrtab_hdr; /* sh_name was set in prep_headers. */ shstrtab_hdr->sh_type = SHT_STRTAB; - shstrtab_hdr->sh_flags = 0; + shstrtab_hdr->sh_flags = bed->elf_strtab_flags; shstrtab_hdr->sh_addr = 0; /* sh_size is set in _bfd_elf_assign_file_positions_for_non_load. */ shstrtab_hdr->sh_entsize = 0; @@ -7461,12 +7588,16 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), } else if (bfd_is_com_section (syms[idx]->section)) { -#ifdef USE_STT_COMMON - if (type == STT_OBJECT) - sym.st_info = ELF_ST_INFO (STB_GLOBAL, STT_COMMON); - else -#endif - sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); + if (type != STT_TLS) + { + if ((abfd->flags & BFD_CONVERT_ELF_COMMON)) + type = ((abfd->flags & BFD_USE_ELF_STT_COMMON) + ? STT_COMMON : STT_OBJECT); + else + type = ((flags & BSF_ELF_COMMON) != 0 + ? STT_COMMON : STT_OBJECT); + } + sym.st_info = ELF_ST_INFO (STB_GLOBAL, type); } else if (bfd_is_und_section (syms[idx]->section)) sym.st_info = ELF_ST_INFO (((flags & BSF_WEAK) @@ -7538,8 +7669,7 @@ Unable to find equivalent output section for symbol '%s' from section '%s'"), *sttp = stt; symstrtab_hdr->sh_size = _bfd_elf_strtab_size (stt); symstrtab_hdr->sh_type = SHT_STRTAB; - - symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_flags = bed->elf_strtab_flags; symstrtab_hdr->sh_addr = 0; symstrtab_hdr->sh_entsize = 0; symstrtab_hdr->sh_link = 0; @@ -9287,6 +9417,13 @@ elfcore_grok_note (bfd *abfd, Elf_Internal_Note *note) case NT_SIGINFO: return elfcore_make_note_pseudosection (abfd, ".note.linuxcore.siginfo", note); + + case NT_FREEBSD_THRMISC: + if (note->namesz == 8 + && strcmp (note->namedata, "FreeBSD") == 0) + return elfcore_make_note_pseudosection (abfd, ".thrmisc", note); + else + return TRUE; } } @@ -9784,9 +9921,7 @@ elfcore_write_linux_prpsinfo32 { struct elf_external_linux_prpsinfo32 data; - memset (&data, 0, sizeof (data)); - LINUX_PRPSINFO32_SWAP_FIELDS (abfd, prpsinfo, data); - + swap_linux_prpsinfo32_out (abfd, prpsinfo, &data); return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO, &data, sizeof (data)); } @@ -9798,9 +9933,7 @@ elfcore_write_linux_prpsinfo64 { struct elf_external_linux_prpsinfo64 data; - memset (&data, 0, sizeof (data)); - LINUX_PRPSINFO64_SWAP_FIELDS (abfd, prpsinfo, data); - + swap_linux_prpsinfo64_out (abfd, prpsinfo, &data); return elfcore_write_note (abfd, buf, bufsiz, "CORE", NT_PRPSINFO, &data, sizeof (data)); } @@ -10448,6 +10581,12 @@ _bfd_elf_rel_local_sym (bfd *abfd, sym->st_value + addend); } +/* Adjust an address within a section. Given OFFSET within SEC, return + the new offset within the section, based upon changes made to the + section. Returns -1 if the offset is now invalid. + The offset (in abnd out) is in target sized bytes, however big a + byte may be. */ + bfd_vma _bfd_elf_section_offset (bfd *abfd, struct bfd_link_info *info, @@ -10461,12 +10600,17 @@ _bfd_elf_section_offset (bfd *abfd, offset); case SEC_INFO_TYPE_EH_FRAME: return _bfd_elf_eh_frame_section_offset (abfd, info, sec, offset); + default: if ((sec->flags & SEC_ELF_REVERSE_COPY) != 0) { + /* Reverse the offset. */ const struct elf_backend_data *bed = get_elf_backend_data (abfd); bfd_size_type address_size = bed->s->arch_size / 8; - offset = sec->size - offset - address_size; + + /* address_size and sec->size are in octets. Convert + to bytes before subtracting the original offset. */ + offset = (sec->size - address_size) / bfd_octets_per_byte (abfd) - offset; } return offset; }