1
1
mirror of https://github.com/rui314/mold.git synced 2024-11-11 16:58:12 +03:00
mold/input_files.cc

454 lines
12 KiB
C++
Raw Normal View History

2020-10-20 08:54:35 +03:00
#include "mold.h"
2020-10-04 12:00:33 +03:00
using namespace llvm;
2020-10-09 14:47:45 +03:00
using namespace llvm::ELF;
2020-10-04 12:00:33 +03:00
2020-10-13 14:35:35 +03:00
std::atomic_int num_defined;
std::atomic_int num_undefined;
2020-10-23 07:17:21 +03:00
std::atomic_int num_all_syms;
2020-10-22 19:14:11 +03:00
std::atomic_int num_comdats;
2020-10-23 07:17:21 +03:00
std::atomic_int num_regular_sections;
2020-10-10 13:15:16 +03:00
std::atomic_int num_files;
2020-10-23 07:23:12 +03:00
std::atomic_int num_relocs_alloc;
2020-10-22 18:52:36 +03:00
std::atomic_int num_string_pieces;
2020-10-10 13:15:16 +03:00
2020-10-14 12:42:54 +03:00
ObjectFile::ObjectFile(MemoryBufferRef mb, StringRef archive_name)
2020-10-16 10:38:03 +03:00
: mb(mb), archive_name(archive_name),
2020-10-29 10:48:17 +03:00
obj(check(ELFFile<ELF64LE>::create(mb.getBuffer()))) {}
2020-10-04 12:00:33 +03:00
2020-10-09 14:47:45 +03:00
MemoryBufferRef readFile(StringRef path) {
auto mbOrErr = MemoryBuffer::getFile(path, -1, false);
if (auto ec = mbOrErr.getError())
error("cannot open " + path + ": " + ec.message());
2020-10-04 12:00:33 +03:00
2020-10-09 14:47:45 +03:00
std::unique_ptr<MemoryBuffer> &mb = *mbOrErr;
MemoryBufferRef mbref = mb->getMemBufferRef();
mb.release();
return mbref;
}
static const ELF64LE::Shdr
*findSection(ArrayRef<ELF64LE::Shdr> sections, u32 type) {
2020-10-09 14:47:45 +03:00
for (const ELF64LE::Shdr &sec : sections)
if (sec.sh_type == type)
return &sec;
return nullptr;
}
2020-10-19 14:05:34 +03:00
void ObjectFile::initialize_sections() {
StringRef section_strtab = CHECK(obj.getSectionStringTable(elf_sections), this);
2020-10-19 14:17:32 +03:00
sections.resize(elf_sections.size());
for (int i = 0; i < elf_sections.size(); i++) {
const ELF64LE::Shdr &shdr = elf_sections[i];
2020-10-22 16:42:09 +03:00
if ((shdr.sh_flags & SHF_EXCLUDE) && !(shdr.sh_flags & SHF_ALLOC))
continue;
2020-10-19 14:17:32 +03:00
switch (shdr.sh_type) {
case SHT_GROUP: {
// Get the signature of this section group.
if (shdr.sh_info >= elf_syms.size())
error(toString(this) + ": invalid symbol index");
const ELF64LE::Sym &sym = elf_syms[shdr.sh_info];
2020-10-26 15:44:08 +03:00
StringRef signature = CHECK(sym.getName(symbol_strtab), this);
2020-10-27 14:15:57 +03:00
2020-10-19 15:32:57 +03:00
// Get comdat group members.
ArrayRef<ELF64LE::Word> entries =
CHECK(obj.template getSectionContentsAsArray<ELF64LE::Word>(shdr), this);
if (entries.empty())
error(toString(this) + ": empty SHT_GROUP");
if (entries[0] == 0)
continue;
if (entries[0] != GRP_COMDAT)
error(toString(this) + ": unsupported SHT_GROUP format");
2020-10-19 14:17:32 +03:00
static ConcurrentMap<ComdatGroup> map;
2020-10-26 09:37:12 +03:00
ComdatGroup *group = map.insert(signature, ComdatGroup(nullptr, 0));
comdat_groups.push_back({group, i});
2020-10-26 08:46:07 +03:00
// num_comdats++;
2020-10-19 15:32:57 +03:00
break;
2020-10-19 14:17:32 +03:00
}
2020-10-19 16:55:52 +03:00
case SHT_SYMTAB_SHNDX:
error(toString(this) + ": SHT_SYMTAB_SHNDX section is not supported");
break;
case SHT_SYMTAB:
case SHT_STRTAB:
case SHT_REL:
case SHT_RELA:
case SHT_NULL:
break;
2020-10-19 14:17:32 +03:00
default: {
2020-10-26 08:46:07 +03:00
// num_regular_sections++;
2020-10-27 07:52:10 +03:00
#if 0
2020-10-22 18:52:36 +03:00
if ((shdr.sh_flags & SHF_STRINGS) && !(shdr.sh_flags & SHF_WRITE) &&
shdr.sh_entsize == 1) {
2020-10-22 18:34:46 +03:00
read_string_pieces(shdr);
break;
}
2020-10-27 07:52:10 +03:00
#endif
2020-10-22 18:34:46 +03:00
2020-10-19 14:17:32 +03:00
StringRef name = CHECK(obj.getSectionName(shdr, section_strtab), this);
2020-10-25 03:29:03 +03:00
this->sections[i] = new InputSection(this, shdr, name);
2020-10-19 14:17:32 +03:00
break;
}
}
2020-10-13 14:35:35 +03:00
}
2020-10-20 04:32:32 +03:00
for (int i = 0; i < elf_sections.size(); i++) {
const ELF64LE::Shdr &shdr = elf_sections[i];
if (shdr.sh_type != SHT_RELA)
continue;
if (shdr.sh_info >= sections.size())
error(toString(this) + ": invalid relocated section index: " +
Twine(shdr.sh_info));
InputSection *target = sections[shdr.sh_info];
2020-10-23 07:23:12 +03:00
if (target) {
2020-10-20 04:32:32 +03:00
target->rels = CHECK(obj.relas(shdr), this);
2020-10-26 08:46:07 +03:00
// if (target->shdr.sh_flags & SHF_ALLOC)
// num_relocs_alloc += target->rels.size();
2020-10-23 07:23:12 +03:00
}
2020-10-20 04:32:32 +03:00
}
2020-10-19 14:05:34 +03:00
}
2020-10-09 14:47:45 +03:00
2020-10-19 14:05:34 +03:00
void ObjectFile::initialize_symbols() {
2020-10-27 14:15:57 +03:00
local_symbols.reserve(first_global);
for (int i = 0; i < first_global; i++) {
const ELF64LE::Sym &esym = elf_syms[i];
StringRef name = CHECK(esym.getName(symbol_strtab), this);
2020-10-27 14:24:28 +03:00
local_symbols.push_back(name);
2020-10-27 16:22:07 +03:00
2020-10-27 19:57:57 +03:00
if (esym.getType() != STT_SECTION) {
2020-10-27 16:22:07 +03:00
local_strtab_size += name.size() + 1;
2020-10-27 19:57:57 +03:00
local_symtab_size += sizeof(ELF64LE::Sym);
}
2020-10-27 14:15:57 +03:00
}
2020-10-27 10:40:05 +03:00
symbols.reserve(elf_syms.size() - first_global);
2020-10-10 06:18:11 +03:00
2020-10-27 10:40:05 +03:00
for (int i = first_global; i < elf_syms.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
StringRef name = CHECK(esym.getName(symbol_strtab), this);
symbols.push_back(Symbol::intern(name));
if (esym.st_shndx == SHN_COMMON)
2020-10-27 02:45:20 +03:00
has_common_symbol = true;
2020-10-09 17:26:26 +03:00
}
2020-10-10 06:18:11 +03:00
}
void ObjectFile::remove_comdat_members(u32 section_idx) {
const ELF64LE::Shdr &shdr = elf_sections[section_idx];
ArrayRef<ELF64LE::Word> entries =
CHECK(obj.template getSectionContentsAsArray<ELF64LE::Word>(shdr), this);
for (u32 i : entries)
sections[i] = nullptr;
}
2020-10-22 18:34:46 +03:00
void ObjectFile::read_string_pieces(const ELF64LE::Shdr &shdr) {
2020-10-22 18:52:36 +03:00
static ConcurrentMap<StringPiece> map1;
static ConcurrentMap<StringPiece> map2;
bool is_alloc = shdr.sh_type & SHF_ALLOC;
ConcurrentMap<StringPiece> &map = is_alloc ? map1 : map2;
2020-10-22 18:34:46 +03:00
2020-10-29 16:32:55 +03:00
ArrayRef<u8> arr = CHECK(obj.getSectionContents(shdr), this);
2020-10-22 18:34:46 +03:00
StringRef data((const char *)&arr[0], arr.size());
while (!data.empty()) {
size_t end = data.find('\0');
if (end == StringRef::npos)
error(toString(this) + ": string is not null terminated");
StringRef substr = data.substr(0, end + 1);
StringPiece *piece = map.insert(substr, StringPiece(substr));
2020-10-22 18:52:36 +03:00
if (is_alloc)
merged_strings_alloc.push_back(piece);
else
merged_strings_noalloc.push_back(piece);
2020-10-22 18:34:46 +03:00
data = data.substr(end + 1);
2020-10-26 08:46:07 +03:00
// num_string_pieces++;
2020-10-22 18:34:46 +03:00
}
}
2020-10-19 14:05:34 +03:00
void ObjectFile::parse() {
num_files++;
2020-10-19 14:17:32 +03:00
bool is_dso = (identify_magic(mb.getBuffer()) == file_magic::elf_shared_object);
elf_sections = CHECK(obj.sections(), this);
symtab_sec = findSection(elf_sections, is_dso ? SHT_DYNSYM : SHT_SYMTAB);
2020-10-26 15:44:08 +03:00
if (symtab_sec) {
first_global = symtab_sec->sh_info;
elf_syms = CHECK(obj.symbols(symtab_sec), this);
symbol_strtab = CHECK(obj.getStringTableForSymtab(*symtab_sec, elf_sections), this);
}
2020-10-19 14:17:32 +03:00
2020-10-26 08:46:07 +03:00
// num_all_syms += elf_syms.size();
2020-10-23 07:17:21 +03:00
2020-10-19 14:05:34 +03:00
initialize_sections();
2020-10-26 15:44:08 +03:00
if (symtab_sec)
initialize_symbols();
2020-10-19 14:05:34 +03:00
}
2020-10-10 06:18:11 +03:00
void ObjectFile::register_defined_symbols() {
2020-10-27 10:36:53 +03:00
for (int i = 0; i < symbols.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[first_global + i];
2020-10-27 10:35:14 +03:00
Symbol &sym = *symbols[i];
2020-10-30 10:00:25 +03:00
if (esym.isDefined()) {
// num_defined++;
2020-10-18 13:00:39 +03:00
2020-10-30 10:00:25 +03:00
InputSection *isec = nullptr;
if (!esym.isAbsolute() && !esym.isCommon())
isec = sections[esym.st_shndx];
2020-10-26 16:07:51 +03:00
2020-10-30 10:00:25 +03:00
bool is_weak = (esym.getBinding() == STB_WEAK);
2020-10-30 09:54:12 +03:00
2020-10-30 10:00:25 +03:00
std::lock_guard lock(sym.mu);
2020-10-27 10:35:14 +03:00
2020-10-30 10:00:25 +03:00
bool is_new = !sym.file;
bool win = sym.is_weak && !is_weak;
bool tie_but_higher_priority = this->priority < sym.file->priority;
2020-10-30 09:38:13 +03:00
2020-10-30 10:00:25 +03:00
if (is_new || win || tie_but_higher_priority) {
sym.file = this;
sym.input_section = isec;
sym.value = esym.st_value;
sym.visibility = esym.getVisibility();
sym.is_weak = is_weak;
}
2020-10-26 09:15:03 +03:00
}
2020-10-13 14:35:35 +03:00
}
}
2020-10-28 13:34:32 +03:00
void
ObjectFile::register_undefined_symbols(tbb::parallel_do_feeder<ObjectFile *> &feeder) {
2020-10-18 15:03:51 +03:00
if (is_alive.exchange(true))
2020-10-18 14:19:57 +03:00
return;
2020-10-27 10:36:53 +03:00
for (int i = 0; i < symbols.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[first_global + i];
Symbol &sym = *symbols[i];
2020-10-30 10:00:25 +03:00
if (esym.isUndefined() && esym.getBinding() != STB_WEAK &&
sym.file && sym.file->is_in_archive() && !sym.file->is_alive) {
// num_undefined++;
2020-10-30 10:55:59 +03:00
#if 1
2020-10-28 13:27:23 +03:00
llvm::outs() << toString(this) << " loads " << toString(sym.file)
<< " for " << sym.name << "\n";
#endif
2020-10-28 13:34:32 +03:00
feeder.add(sym.file);
2020-10-28 13:27:23 +03:00
}
2020-10-09 16:29:25 +03:00
}
2020-10-09 14:47:45 +03:00
}
2020-10-30 10:00:25 +03:00
void ObjectFile::hanlde_undefined_weak_symbols() {
if (!is_alive)
return;
for (int i = 0; i < symbols.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[first_global + i];
Symbol &sym = *symbols[i];
if (esym.isUndefined() && esym.getBinding() == STB_WEAK) {
std::lock_guard lock(sym.mu);
2020-10-30 10:15:14 +03:00
bool is_new = !sym.file || sym.file->is_in_archive();
2020-10-30 10:00:25 +03:00
bool tie_but_higher_priority =
sym.is_undef_weak && this->priority < sym.file->priority;
if (is_new || tie_but_higher_priority) {
sym.file = this;
sym.input_section = nullptr;
sym.value = 0;
sym.visibility = esym.getVisibility();
sym.is_undef_weak = true;
}
}
}
}
2020-10-19 15:50:33 +03:00
void ObjectFile::eliminate_duplicate_comdat_groups() {
for (auto &pair : comdat_groups) {
ComdatGroup *g = pair.first;
u32 section_idx = pair.second;
2020-10-23 06:43:22 +03:00
ObjectFile *other = g->file;
if (other && other->priority < this->priority) {
this->remove_comdat_members(section_idx);
2020-10-27 14:15:57 +03:00
continue;
2020-10-23 06:43:22 +03:00
}
2020-10-23 06:41:17 +03:00
2020-10-23 06:43:22 +03:00
ObjectFile *file;
u32 idx;
2020-10-23 06:41:17 +03:00
2020-10-23 06:24:25 +03:00
{
2020-10-28 13:51:49 +03:00
std::lock_guard lock(g->mu);
2020-10-23 06:24:25 +03:00
if (g->file == nullptr) {
g->file = this;
g->section_idx = section_idx;
2020-10-23 06:24:52 +03:00
continue;
}
2020-10-23 06:43:22 +03:00
if (g->file.load()->priority < this->priority) {
2020-10-23 06:24:25 +03:00
file = this;
idx = section_idx;
} else {
file = g->file;
idx = g->section_idx;
2020-10-23 06:41:17 +03:00
g->file = this;
g->section_idx = section_idx;
2020-10-23 06:24:25 +03:00
}
2020-10-19 15:50:33 +03:00
}
2020-10-23 06:24:52 +03:00
file->remove_comdat_members(idx);
2020-10-19 15:50:33 +03:00
}
}
2020-10-27 06:50:25 +03:00
void ObjectFile::convert_common_symbols() {
if (!has_common_symbol)
return;
2020-10-27 07:52:10 +03:00
2020-10-29 07:31:41 +03:00
static OutputSection *bss =
OutputSection::get_instance(".bss", SHF_WRITE | SHF_ALLOC, SHT_NOBITS);
2020-10-27 07:52:10 +03:00
for (int i = first_global; i < elf_syms.size(); i++) {
if (elf_syms[i].st_shndx != SHN_COMMON)
2020-10-27 07:52:10 +03:00
continue;
Symbol *sym = symbols[i - first_global];
if (sym->file != this)
2020-10-27 07:52:10 +03:00
continue;
auto *shdr = new ELF64LE::Shdr;
memset(shdr, 0, sizeof(*shdr));
shdr->sh_flags = SHF_ALLOC;
shdr->sh_type = SHT_NOBITS;
2020-10-29 07:31:41 +03:00
shdr->sh_size = elf_syms[i].st_size;
2020-10-27 07:52:10 +03:00
shdr->sh_addralign = 1;
auto *isec = new InputSection(this, *shdr, ".bss");
2020-10-29 07:31:41 +03:00
isec->output_section = bss;
2020-10-27 07:52:10 +03:00
sections.push_back(isec);
sym->input_section = isec;
sym->value = 0;
2020-10-27 07:52:10 +03:00
}
2020-10-27 06:50:25 +03:00
}
2020-10-29 10:41:17 +03:00
std::tuple<u64, u64> ObjectFile::scan_relocations() {
u64 num_got = 0;
u64 num_plt = 0;
for (InputSection *isec : sections) {
if (isec) {
auto [got, plt] = isec->scan_relocations();
num_got += got;
num_got += plt;
}
}
return {num_got, num_plt};
2020-10-23 03:21:40 +03:00
}
2020-10-26 08:57:22 +03:00
void ObjectFile::fix_sym_addrs() {
2020-10-27 10:37:56 +03:00
for (Symbol *sym : symbols) {
if (sym->file != this)
2020-10-26 08:57:22 +03:00
continue;
2020-10-27 14:15:57 +03:00
InputSection *isec = sym->input_section;
2020-10-27 08:08:06 +03:00
2020-10-27 08:14:27 +03:00
if (isec) {
OutputSection *osec = isec->output_section;
sym->addr = osec->shdr.sh_addr + isec->offset + sym->value;
2020-10-27 08:14:27 +03:00
} else {
// Absolute symbol
sym->addr = sym->value;
2020-10-27 07:52:10 +03:00
}
2020-10-26 08:57:22 +03:00
}
}
2020-10-27 14:58:28 +03:00
void ObjectFile::compute_symtab() {
2020-10-27 16:22:07 +03:00
for (int i = first_global; i < elf_syms.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
Symbol &sym = *symbols[i - first_global];
if (esym.getType() != STT_SECTION && sym.file == this) {
global_strtab_size += sym.name.size() + 1;
2020-10-27 16:08:49 +03:00
global_symtab_size += sizeof(ELF64LE::Sym);
2020-10-27 14:58:28 +03:00
}
}
2020-10-27 14:15:57 +03:00
}
2020-10-27 16:08:49 +03:00
void
2020-10-29 16:32:55 +03:00
ObjectFile::write_local_symtab(u8 *buf, u64 symtab_off, u64 strtab_off) {
u8 *symtab = buf + out::symtab->shdr.sh_offset;
u8 *strtab = buf + out::strtab->shdr.sh_offset;
2020-10-27 15:38:52 +03:00
for (int i = 0; i < first_global; i++) {
const ELF64LE::Sym &esym = elf_syms[i];
2020-10-27 16:22:07 +03:00
if (esym.getType() == STT_SECTION)
continue;
2020-10-27 15:38:52 +03:00
StringRef name = local_symbols[i];
auto *ent = (ELF64LE::Sym *)(symtab + symtab_off);
*ent = esym;
2020-10-29 10:17:42 +03:00
if (esym.st_shndx != SHN_ABS && esym.st_shndx != SHN_COMMON)
if (InputSection *isec = sections[esym.st_shndx])
if (OutputSection *osec = isec->output_section)
ent->st_shndx = osec->idx;
2020-10-27 15:38:52 +03:00
ent->st_name = strtab_off;
2020-10-28 14:13:40 +03:00
ent->st_value = get_symbol_addr(i);
2020-10-27 15:38:52 +03:00
symtab_off += sizeof(ELF64LE::Sym);
2020-10-27 18:26:31 +03:00
memcpy_nontemporal(strtab + strtab_off, name.data(), name.size());
2020-10-27 15:38:52 +03:00
strtab_off += name.size() + 1;
}
2020-10-27 15:45:19 +03:00
}
2020-10-27 16:08:49 +03:00
void
2020-10-29 16:32:55 +03:00
ObjectFile::write_global_symtab(u8 *buf, u64 symtab_off, u64 strtab_off) {
u8 *symtab = buf + out::symtab->shdr.sh_offset;
u8 *strtab = buf + out::strtab->shdr.sh_offset;
2020-10-27 15:38:52 +03:00
for (int i = first_global; i < elf_syms.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
Symbol &sym = *symbols[i - first_global];
2020-10-27 16:22:07 +03:00
if (esym.getType() == STT_SECTION || sym.file != this)
2020-10-27 15:38:52 +03:00
continue;
auto *ent = (ELF64LE::Sym *)(symtab + symtab_off);
*ent = esym;
2020-10-29 08:54:48 +03:00
if (InputSection *isec = sym.input_section)
2020-10-29 09:30:41 +03:00
ent->st_shndx = isec->output_section->shndx;
2020-10-27 15:38:52 +03:00
ent->st_name = strtab_off;
2020-10-30 09:38:13 +03:00
ent->st_value = sym.addr;
2020-10-27 15:38:52 +03:00
symtab_off += sizeof(ELF64LE::Sym);
2020-10-27 18:26:31 +03:00
memcpy_nontemporal(strtab + strtab_off, sym.name.data(), sym.name.size());
2020-10-27 15:38:52 +03:00
strtab_off += sym.name.size() + 1;
}
}
2020-10-18 13:05:28 +03:00
StringRef ObjectFile::get_filename() {
return mb.getBufferIdentifier();
}
bool ObjectFile::is_in_archive() {
return !archive_name.empty();
}
2020-10-09 14:47:45 +03:00
std::string toString(ObjectFile *obj) {
2020-10-14 13:04:36 +03:00
StringRef s = obj->get_filename();
if (obj->archive_name == "")
return s.str();
return (obj->archive_name + ":" + s).str();
2020-10-09 14:47:45 +03:00
}