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-10 13:15:16 +03:00
|
|
|
std::atomic_int num_files;
|
|
|
|
|
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),
|
|
|
|
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, uint32_t type) {
|
|
|
|
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];
|
|
|
|
|
|
|
|
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];
|
|
|
|
StringRef signature = CHECK(sym.getName(string_table), this);
|
|
|
|
|
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
|
|
|
|
2020-10-19 15:50:33 +03:00
|
|
|
static ConcurrentMap<bool> map;
|
|
|
|
bool *handle = map.insert(signature, false);
|
|
|
|
comdat_groups.push_back({handle, entries});
|
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: {
|
|
|
|
StringRef name = CHECK(obj.getSectionName(shdr, section_strtab), this);
|
|
|
|
this->sections[i] = new InputSection(this, &shdr, name);
|
|
|
|
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];
|
|
|
|
if (target)
|
|
|
|
target->rels = CHECK(obj.relas(shdr), this);
|
|
|
|
}
|
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-10 10:49:02 +03:00
|
|
|
if (!symtab_sec)
|
|
|
|
return;
|
|
|
|
|
2020-10-13 14:35:35 +03:00
|
|
|
this->symbols.resize(elf_syms.size());
|
2020-10-10 06:18:11 +03:00
|
|
|
|
2020-10-09 17:26:26 +03:00
|
|
|
for (int i = 0; i < elf_syms.size(); i++) {
|
2020-10-18 14:19:57 +03:00
|
|
|
if (i < first_global)
|
|
|
|
continue;
|
|
|
|
StringRef name = CHECK(this->elf_syms[i].getName(string_table), this);
|
2020-10-19 15:50:33 +03:00
|
|
|
|
|
|
|
static ConcurrentMap<Symbol> map;
|
2020-10-19 15:36:07 +03:00
|
|
|
symbols[i] = map.insert(name, Symbol(name));
|
2020-10-09 17:26:26 +03:00
|
|
|
}
|
2020-10-10 06:18:11 +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);
|
|
|
|
first_global = symtab_sec->sh_info;
|
|
|
|
elf_syms = CHECK(obj.symbols(symtab_sec), this);
|
|
|
|
string_table = CHECK(obj.getStringTableForSymtab(*symtab_sec, elf_sections), this);
|
|
|
|
|
2020-10-19 14:05:34 +03:00
|
|
|
initialize_sections();
|
|
|
|
initialize_symbols();
|
|
|
|
}
|
|
|
|
|
2020-10-18 14:19:57 +03:00
|
|
|
class Spinlock {
|
|
|
|
public:
|
|
|
|
Spinlock(std::atomic_flag &lock) : lock(lock) {
|
|
|
|
while (lock.test_and_set(std::memory_order_acquire));
|
|
|
|
}
|
|
|
|
|
|
|
|
~Spinlock() {
|
|
|
|
lock.clear(std::memory_order_release);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::atomic_flag &lock;
|
|
|
|
};
|
|
|
|
|
2020-10-10 06:18:11 +03:00
|
|
|
void ObjectFile::register_defined_symbols() {
|
2020-10-18 14:19:57 +03:00
|
|
|
for (int i = first_global; i < symbols.size(); i++) {
|
2020-10-13 14:35:35 +03:00
|
|
|
if (!elf_syms[i].isDefined())
|
|
|
|
continue;
|
2020-10-18 14:19:57 +03:00
|
|
|
num_defined++;
|
2020-10-18 13:00:39 +03:00
|
|
|
|
2020-10-18 14:19:57 +03:00
|
|
|
Symbol *sym = symbols[i];
|
|
|
|
Spinlock lock(sym->lock);
|
2020-10-18 13:17:44 +03:00
|
|
|
|
2020-10-18 14:19:57 +03:00
|
|
|
if (sym->file && sym->file->priority < this->priority)
|
|
|
|
continue;
|
|
|
|
sym->file = this;
|
2020-10-13 14:35:35 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ObjectFile::register_undefined_symbols() {
|
2020-10-18 15:03:51 +03:00
|
|
|
if (is_alive.exchange(true))
|
2020-10-18 14:19:57 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
for (int i = first_global; i < symbols.size(); i++) {
|
2020-10-13 14:35:35 +03:00
|
|
|
if (elf_syms[i].isDefined())
|
|
|
|
continue;
|
|
|
|
num_undefined++;
|
2020-10-18 14:19:57 +03:00
|
|
|
|
|
|
|
Symbol *sym = symbols[i];
|
2020-10-18 15:03:51 +03:00
|
|
|
if (sym->file && sym->file->is_in_archive() && !sym->file->is_alive)
|
2020-10-18 14:19:57 +03:00
|
|
|
sym->file->register_undefined_symbols();
|
2020-10-09 16:29:25 +03:00
|
|
|
}
|
2020-10-09 14:47:45 +03:00
|
|
|
}
|
|
|
|
|
2020-10-19 15:50:33 +03:00
|
|
|
void ObjectFile::eliminate_duplicate_comdat_groups() {
|
|
|
|
for (std::pair<bool *, ArrayRef<ELF64LE::Word>> pair : comdat_groups) {
|
|
|
|
bool *handle = pair.first;
|
|
|
|
ArrayRef<ELF64LE::Word> entries = pair.second;
|
|
|
|
|
|
|
|
if (!*handle) {
|
|
|
|
*handle = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i : entries)
|
|
|
|
sections[i] = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|