1
1
mirror of https://github.com/rui314/mold.git synced 2024-12-27 18:34:15 +03:00
mold/object_file.cc

613 lines
17 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
2020-11-03 14:49:30 +03:00
#include "llvm/BinaryFormat/Magic.h"
2020-11-04 04:39:17 +03:00
#include <cstring>
2020-11-11 08:43:07 +03:00
#include <regex>
2020-11-04 04:39:17 +03:00
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-14 12:42:54 +03:00
ObjectFile::ObjectFile(MemoryBufferRef mb, StringRef archive_name)
2020-11-01 07:54:56 +03:00
: mb(mb), name(mb.getBufferIdentifier()), archive_name(archive_name),
2020-11-05 06:34:59 +03:00
obj(check(ELFFile<ELF64LE>::create(mb.getBuffer()))),
2020-11-07 18:53:28 +03:00
is_alive(archive_name == ""), is_in_archive(archive_name != "") {}
2020-10-04 12:00:33 +03:00
2020-10-09 14:47:45 +03:00
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-11-12 18:02:33 +03:00
void ObjectFile::initialize_soname() {
for (const ELF64LE::Shdr &shdr : elf_sections) {
if (shdr.sh_type != SHT_DYNAMIC)
continue;
ArrayRef<ELF64LE::Dyn> tags =
CHECK(obj.template getSectionContentsAsArray<ELF64LE::Dyn>(shdr), this);
for (const ELF64LE::Dyn &dyn : tags) {
if (dyn.d_tag == DT_NEEDED) {
this->soname = StringRef(symbol_strtab.data() + dyn.d_un.d_val);
return;
}
}
}
}
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
2020-11-07 05:53:32 +03:00
// Read sections
2020-10-19 14:17:32 +03:00
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));
2020-11-08 12:20:48 +03:00
comdat_groups.push_back({group, entries});
2020-11-03 11:48:15 +03:00
2020-11-03 11:52:39 +03:00
static Counter counter("comdats");
2020-11-03 11:48:15 +03:00
counter.inc();
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-11-03 11:52:39 +03:00
static Counter counter("regular_sections");
counter.inc();
2020-11-07 04:39:29 +03:00
StringRef name = CHECK(obj.getSectionName(shdr, section_strtab), this);
2020-11-07 05:41:14 +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
2020-11-07 05:53:32 +03:00
// Attach relocation sections to their target sections.
2020-11-03 15:09:21 +03:00
for (const ELF64LE::Shdr &shdr : elf_sections) {
2020-10-20 04:32:32 +03:00
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-11-03 11:52:39 +03:00
if (target->shdr.sh_flags & SHF_ALLOC) {
2020-11-03 15:09:21 +03:00
static Counter counter("relocs_alloc");
2020-11-03 11:52:39 +03:00
counter.inc(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-11-03 11:52:39 +03:00
static Counter counter("all_syms");
counter.inc(elf_syms.size());
2020-11-03 08:53:32 +03:00
symbols.reserve(elf_syms.size());
2020-10-27 14:15:57 +03:00
local_symbols.reserve(first_global);
2020-11-03 09:43:23 +03:00
// First symbol entry is always null
local_symbols.emplace_back("");
symbols.push_back(&local_symbols.back());
2020-11-07 06:31:54 +03:00
// Initialize local symbols
2020-11-03 09:43:23 +03:00
for (int i = 1; i < first_global; i++) {
2020-10-27 14:15:57 +03:00
const ELF64LE::Sym &esym = elf_syms[i];
StringRef name = CHECK(esym.getName(symbol_strtab), this);
2020-11-03 09:19:54 +03:00
2020-11-03 08:53:32 +03:00
local_symbols.emplace_back(name);
2020-11-03 09:08:05 +03:00
Symbol &sym = local_symbols.back();
sym.file = this;
sym.type = esym.getType();
2020-11-06 06:52:16 +03:00
sym.value = esym.st_value;
2020-11-03 09:08:05 +03:00
2020-11-03 16:36:16 +03:00
if (!esym.isAbsolute()) {
if (esym.isCommon())
2020-11-03 09:08:05 +03:00
error("common local symbol?");
sym.input_section = sections[esym.st_shndx];
}
2020-11-03 08:53:32 +03:00
symbols.push_back(&local_symbols.back());
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-11-07 06:31:54 +03:00
// Initialize global symbols
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));
2020-11-03 16:36:16 +03:00
if (esym.isCommon())
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
}
2020-11-07 13:23:14 +03:00
static const StringPieceRef *
binary_search(ArrayRef<StringPieceRef> pieces, u32 offset) {
if (offset < pieces[0].input_offset)
2020-11-07 06:14:37 +03:00
return nullptr;
while (pieces.size() > 1) {
u32 mid = pieces.size() / 2;
2020-11-07 13:23:14 +03:00
const StringPieceRef &ref = pieces[mid];
2020-11-07 06:14:37 +03:00
2020-11-07 13:23:14 +03:00
if (offset < ref.input_offset)
2020-11-07 06:14:37 +03:00
pieces = pieces.slice(0, mid);
else
pieces = pieces.slice(mid);
}
2020-11-07 13:23:14 +03:00
return &pieces[0];
2020-11-07 06:14:37 +03:00
}
2020-11-08 08:13:59 +03:00
static bool is_mergeable(const ELF64LE::Shdr &shdr) {
return (shdr.sh_flags & SHF_MERGE) &&
(shdr.sh_flags & SHF_STRINGS) &&
shdr.sh_entsize == 1;
}
2020-11-07 05:53:32 +03:00
void ObjectFile::initialize_mergeable_sections() {
2020-11-08 08:13:59 +03:00
// Count the number of mergeable input sections.
u32 num_mergeable = 0;
2020-11-07 05:53:32 +03:00
for (InputSection *isec : sections)
2020-11-08 08:13:59 +03:00
if (isec && is_mergeable(isec->shdr))
num_mergeable++;
mergeable_sections.reserve(num_mergeable);
for (int i = 0; i < sections.size(); i++) {
InputSection *isec = sections[i];
if (isec && is_mergeable(isec->shdr)) {
ArrayRef<u8> contents = CHECK(obj.getSectionContents(isec->shdr), this);
mergeable_sections.emplace_back(isec, contents);
2020-11-08 09:56:17 +03:00
isec->mergeable = &mergeable_sections.back();
2020-11-08 08:13:59 +03:00
sections[i] = nullptr;
}
}
2020-11-07 06:14:37 +03:00
// Initialize rel_pieces
for (InputSection *isec : sections) {
if (!isec || isec->rels.empty())
continue;
isec->rel_pieces.resize(isec->rels.size());
for (int i = 0; i < isec->rels.size(); i++) {
const ELF64LE::Rela &rel = isec->rels[i];
2020-11-07 13:23:14 +03:00
switch (rel.getType(false)) {
case R_X86_64_64:
case R_X86_64_PC32:
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_16:
case R_X86_64_PC16:
case R_X86_64_8:
case R_X86_64_PC8:
u32 sym_idx = rel.getSymbol(false);
if (sym_idx >= this->first_global)
continue;
2020-11-07 13:43:41 +03:00
Symbol &sym = *symbols[sym_idx];
2020-11-08 11:55:48 +03:00
if (sym.type != STT_SECTION || !sym.input_section)
2020-11-07 13:43:41 +03:00
continue;
2020-11-08 08:13:59 +03:00
2020-11-08 09:56:17 +03:00
MergeableSection *mergeable = sym.input_section->mergeable;
if (!mergeable)
continue;
2020-11-08 08:13:59 +03:00
2020-11-07 13:43:41 +03:00
u32 offset = sym.value + rel.r_addend;
2020-11-08 09:56:17 +03:00
const StringPieceRef *ref = binary_search(mergeable->pieces, offset);
2020-11-07 13:23:14 +03:00
if (!ref)
error(toString(this) + ": bad relocation at " + std::to_string(sym_idx));
isec->rel_pieces[i].piece = ref->piece;
2020-11-07 14:05:51 +03:00
isec->rel_pieces[i].addend = offset - ref->input_offset;
2020-11-07 13:23:14 +03:00
}
2020-11-07 06:14:37 +03:00
}
}
// Initialize sym_pieces
sym_pieces.resize(elf_syms.size());
for (int i = 0; i < elf_syms.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
if (esym.isAbsolute() || esym.isCommon())
continue;
InputSection *isec = sections[esym.st_shndx];
2020-11-08 08:13:59 +03:00
if (!isec || isec->kind != InputChunk::MERGEABLE)
2020-11-07 06:14:37 +03:00
continue;
2020-11-08 08:13:59 +03:00
ArrayRef<StringPieceRef> pieces = ((MergeableSection *)isec)->pieces;
const StringPieceRef *ref = binary_search(pieces, esym.st_value);
2020-11-07 13:23:14 +03:00
if (!ref)
2020-11-07 06:14:37 +03:00
error(toString(this) + ": bad symbol value");
2020-11-07 13:23:14 +03:00
sym_pieces[i].piece = ref->piece;
2020-11-07 16:42:46 +03:00
sym_pieces[i].addend = esym.st_value - ref->input_offset;
2020-11-07 06:14:37 +03:00
}
2020-11-07 04:39:29 +03:00
}
2020-10-19 14:05:34 +03:00
void ObjectFile::parse() {
2020-11-03 15:27:14 +03:00
is_dso = (identify_magic(mb.getBuffer()) == file_magic::elf_shared_object);
2020-10-19 14:17:32 +03:00
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-11-11 09:52:00 +03:00
sections.resize(elf_sections.size());
2020-11-12 18:02:33 +03:00
if (is_dso)
initialize_soname();
else
2020-11-04 10:54:53 +03:00
initialize_sections();
2020-10-26 15:44:08 +03:00
if (symtab_sec)
initialize_symbols();
2020-11-05 07:05:27 +03:00
if (Counter::enabled) {
static Counter defined("defined_syms");
static Counter undefined("undefined_syms");
for (const ELF64LE::Sym &esym : elf_syms) {
if (esym.isDefined())
defined.inc();
else
undefined.inc();
}
}
2020-10-19 14:05:34 +03:00
}
2020-11-07 16:44:29 +03:00
void ObjectFile::maybe_override_symbol(const ELF64LE::Sym &esym, Symbol &sym, int idx) {
2020-11-05 07:16:33 +03:00
InputSection *isec = nullptr;
if (!esym.isAbsolute() && !esym.isCommon())
isec = sections[esym.st_shndx];
bool is_weak = (esym.getBinding() == STB_WEAK);
std::lock_guard lock(sym.mu);
bool is_new = !sym.file;
bool win = sym.is_placeholder || (sym.is_weak && !is_weak);
bool tie_but_higher_priority =
!is_new && !win && this->priority < sym.file->priority;
if (is_new || win || tie_but_higher_priority) {
sym.file = this;
sym.input_section = isec;
2020-11-07 16:44:29 +03:00
sym.piece_ref = sym_pieces[idx];
2020-11-06 06:52:16 +03:00
sym.value = esym.st_value;
2020-11-05 07:16:33 +03:00
sym.type = esym.getType();
sym.visibility = esym.getVisibility();
sym.is_placeholder = false;
sym.is_weak = is_weak;
sym.is_dso = is_dso;
}
2020-11-05 07:18:17 +03:00
if (UNLIKELY(sym.traced) && sym.file == this)
2020-11-05 07:16:33 +03:00
llvm::outs() << "trace: " << toString(sym.file) << ": definition of "
<< sym.name << "\n";
}
2020-11-05 06:20:16 +03:00
void ObjectFile::resolve_symbols() {
2020-11-03 08:53:32 +03:00
for (int i = first_global; i < symbols.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
2020-11-05 02:59:20 +03:00
if (!esym.isDefined())
continue;
2020-10-27 10:35:14 +03:00
Symbol &sym = *symbols[i];
2020-11-05 07:16:33 +03:00
if (is_in_archive) {
std::lock_guard lock(sym.mu);
bool is_new = !sym.file;
bool tie_but_higher_priority =
sym.is_placeholder && this->priority < sym.file->priority;
2020-10-27 10:35:14 +03:00
2020-11-05 07:16:33 +03:00
if (is_new || tie_but_higher_priority) {
sym.file = this;
sym.is_placeholder = true;
}
} else {
2020-11-07 16:44:29 +03:00
maybe_override_symbol(esym, sym, i);
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
2020-11-05 06:20:16 +03:00
ObjectFile::mark_live_archive_members(tbb::parallel_do_feeder<ObjectFile *> &feeder) {
2020-11-03 08:53:32 +03:00
for (int i = first_global; i < symbols.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
2020-10-27 10:36:53 +03:00
Symbol &sym = *symbols[i];
2020-11-05 07:16:33 +03:00
if (esym.isDefined()) {
if (is_in_archive)
2020-11-07 16:44:29 +03:00
maybe_override_symbol(esym, sym, i);
2020-11-05 07:16:33 +03:00
continue;
}
2020-11-05 02:59:20 +03:00
if (UNLIKELY(sym.traced))
llvm::outs() << "trace: " << toString(this)
<< ": reference to " << sym.name << "\n";
if (esym.getBinding() != STB_WEAK && sym.file &&
2020-11-07 20:03:54 +03:00
!sym.file->is_alive.exchange(true)) {
2020-11-05 02:59:20 +03:00
feeder.add(sym.file);
if (UNLIKELY(sym.traced))
llvm::outs() << "trace: " << toString(this) << " keeps "
<< toString(sym.file) << " for " << sym.name << "\n";
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;
2020-11-03 08:53:32 +03:00
for (int i = first_global; i < symbols.size(); i++) {
const ELF64LE::Sym &esym = elf_syms[i];
2020-10-30 10:00:25 +03:00
Symbol &sym = *symbols[i];
if (esym.isUndefined() && esym.getBinding() == STB_WEAK) {
std::lock_guard lock(sym.mu);
2020-11-01 19:12:22 +03:00
bool is_new = !sym.file || !sym.file->is_alive;
2020-10-30 10:00:25 +03:00
bool tie_but_higher_priority =
2020-11-01 06:45:30 +03:00
!is_new && sym.is_undef_weak && this->priority < sym.file->priority;
2020-10-30 10:00:25 +03:00
if (is_new || tie_but_higher_priority) {
sym.file = this;
sym.input_section = nullptr;
2020-11-06 06:52:16 +03:00
sym.value = 0;
2020-10-30 10:00:25 +03:00
sym.visibility = esym.getVisibility();
sym.is_undef_weak = true;
2020-11-05 02:59:20 +03:00
if (UNLIKELY(sym.traced))
llvm::outs() << "trace: " << toString(this)
<< ": unresolved weak symbol " << sym.name << "\n";
2020-10-30 10:00:25 +03:00
}
}
}
}
2020-11-08 12:17:24 +03:00
void ObjectFile::resolve_comdat_groups() {
for (auto &pair : comdat_groups) {
ComdatGroup *group = pair.first;
ObjectFile *cur = group->file;
while (!cur || cur->priority > this->priority)
if (group->file.compare_exchange_strong(cur, this))
break;
}
}
2020-10-19 15:50:33 +03:00
void ObjectFile::eliminate_duplicate_comdat_groups() {
for (auto &pair : comdat_groups) {
2020-11-08 12:17:24 +03:00
ComdatGroup *group = pair.first;
2020-11-08 12:18:22 +03:00
if (group->file == this)
continue;
2020-11-08 12:20:48 +03:00
ArrayRef<ELF64LE::Word> entries = pair.second;
2020-11-08 12:18:22 +03:00
for (u32 i : entries)
sections[i] = nullptr;
2020-11-08 12:28:49 +03:00
static Counter counter("removed_comdat_mem");
counter.inc(entries.size());
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++) {
2020-11-03 16:36:16 +03:00
if (!elf_syms[i].isCommon())
2020-10-27 07:52:10 +03:00
continue;
2020-11-03 08:53:32 +03:00
Symbol *sym = symbols[i];
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;
2020-11-06 06:52:16 +03:00
sym->value = 0;
2020-10-27 07:52:10 +03:00
}
2020-10-27 06:50:25 +03:00
}
2020-11-06 06:01:52 +03:00
void ObjectFile::scan_relocations() {
2020-11-06 02:49:41 +03:00
for (InputSection *isec : sections)
if (isec)
2020-11-06 06:01:52 +03:00
isec->scan_relocations();
2020-11-06 02:49:41 +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];
2020-11-03 08:53:32 +03:00
Symbol &sym = *symbols[i];
2020-10-27 16:22:07 +03:00
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-11-03 09:57:05 +03:00
void ObjectFile::write_symtab(u8 *buf, u64 symtab_off, u64 strtab_off,
u32 start, u32 end) {
2020-11-11 15:32:41 +03:00
u8 *symtab = buf + out::symtab->shdr.sh_offset;
u8 *strtab = buf + out::strtab->shdr.sh_offset;
2020-10-27 15:38:52 +03:00
2020-11-03 09:57:05 +03:00
for (int i = start; i < end; i++) {
2020-11-03 09:43:23 +03:00
Symbol &sym = *symbols[i];
2020-11-03 09:57:05 +03:00
if (sym.type == STT_SECTION || sym.file != this)
2020-10-27 16:22:07 +03:00
continue;
2020-11-03 09:43:23 +03:00
auto &esym = *(ELF64LE::Sym *)(symtab + symtab_off);
2020-11-06 07:59:29 +03:00
symtab_off += sizeof(ELF64LE::Sym);
2020-11-09 15:32:13 +03:00
memset(&esym, 0, sizeof(esym));
2020-11-03 09:43:23 +03:00
esym.st_name = strtab_off;
2020-11-06 06:50:26 +03:00
esym.st_value = sym.get_addr();
2020-11-03 09:43:23 +03:00
esym.st_size = elf_syms[i].st_size;
esym.st_info = elf_syms[i].st_info;
2020-11-04 08:03:01 +03:00
if (sym.input_section)
esym.st_shndx = sym.input_section->output_section->shndx;
2020-11-04 08:41:40 +03:00
else if (sym.shndx)
esym.st_shndx = sym.shndx;
2020-11-04 08:03:01 +03:00
else
esym.st_shndx = SHN_ABS;
2020-11-03 09:43:23 +03:00
2020-11-11 04:29:54 +03:00
write_string(strtab + strtab_off, sym.name);
2020-11-03 09:52:26 +03:00
strtab_off += sym.name.size() + 1;
2020-10-27 15:38:52 +03:00
}
2020-10-27 15:45:19 +03:00
}
2020-11-03 09:57:05 +03:00
void ObjectFile::write_local_symtab(u8 *buf, u64 symtab_off, u64 strtab_off) {
write_symtab(buf, symtab_off, strtab_off, 1, first_global);
}
2020-10-27 15:38:52 +03:00
2020-11-03 09:57:05 +03:00
void ObjectFile::write_global_symtab(u8 *buf, u64 symtab_off, u64 strtab_off) {
write_symtab(buf, symtab_off, strtab_off, first_global, elf_syms.size());
2020-10-27 15:38:52 +03:00
}
2020-11-04 04:43:05 +03:00
bool is_c_identifier(StringRef name) {
2020-11-11 08:43:07 +03:00
static std::regex re("[a-zA-Z_][a-zA-Z0-9_]*");
return std::regex_match(name.begin(), name.end(), re);
2020-11-04 04:39:17 +03:00
}
2020-11-12 08:40:39 +03:00
ObjectFile *ObjectFile::create_internal_file(std::vector<OutputChunk *> chunks) {
2020-11-03 13:33:46 +03:00
// Create a dummy object file.
constexpr int bufsz = 256;
char *buf = new char[bufsz];
std::unique_ptr<MemoryBuffer> mb =
MemoryBuffer::getMemBuffer(StringRef(buf, bufsz));
auto *obj = new ObjectFile(mb->getMemBufferRef(), "");
obj->name = "<internal>";
mb.release();
// Create linker-synthesized symbols.
2020-11-04 01:12:13 +03:00
auto *elf_syms = new std::vector<ELF64LE::Sym>(1);
2020-11-04 01:16:59 +03:00
obj->symbols.push_back(new Symbol(""));
2020-11-05 02:23:11 +03:00
obj->is_alive = true;
2020-11-03 13:33:46 +03:00
2020-11-04 01:19:27 +03:00
auto add = [&](StringRef name, u8 binding) {
2020-11-03 13:33:46 +03:00
Symbol *sym = Symbol::intern(name);
sym->file = obj;
obj->symbols.push_back(sym);
ELF64LE::Sym esym = {};
esym.setType(STT_NOTYPE);
2020-11-04 01:19:27 +03:00
esym.setBinding(binding);
2020-11-03 13:33:46 +03:00
elf_syms->push_back(esym);
return sym;
};
2020-11-06 04:36:44 +03:00
// Add local symbols
2020-11-04 01:19:27 +03:00
out::__ehdr_start = add("__ehdr_start", STB_LOCAL);
out::__rela_iplt_start = add("__rela_iplt_start", STB_LOCAL);
out::__rela_iplt_end = add("__rela_iplt_end", STB_LOCAL);
out::__init_array_start = add("__init_array_start", STB_LOCAL);
out::__init_array_end = add("__init_array_end", STB_LOCAL);
out::__fini_array_start = add("__fini_array_start", STB_LOCAL);
out::__fini_array_end = add("__fini_array_end", STB_LOCAL);
2020-11-04 01:27:27 +03:00
out::__preinit_array_start = add("__preinit_array_start", STB_LOCAL);
out::__preinit_array_end = add("__preinit_array_end", STB_LOCAL);
2020-11-06 04:11:19 +03:00
2020-11-06 04:36:44 +03:00
// Update metadata
2020-11-10 11:43:04 +03:00
for (int i = 1; i < obj->symbols.size(); i++)
obj->local_strtab_size += obj->symbols[i]->name.size() + 1;
2020-11-10 08:58:50 +03:00
obj->local_symtab_size = sizeof(ELF64LE::Sym) * (obj->symbols.size() - 1);
2020-11-06 04:36:44 +03:00
obj->first_global = obj->symbols.size();
// Add global symbols
2020-11-06 04:11:19 +03:00
out::__bss_start = add("__bss_start", STB_GLOBAL);
2020-11-04 07:17:05 +03:00
out::_end = add("_end", STB_GLOBAL);
out::_etext = add("_etext", STB_GLOBAL);
out::_edata = add("_edata", STB_GLOBAL);
2020-11-12 08:40:39 +03:00
std::sort(chunks.begin(), chunks.end(), [](OutputChunk *x, OutputChunk *y) {
return x->name < y->name;
});
2020-11-11 08:13:39 +03:00
for (OutputChunk *chunk : chunks) {
2020-11-04 04:43:05 +03:00
if (!is_c_identifier(chunk->name))
continue;
auto *start = new std::string(("__start_" + chunk->name).str());
auto *stop = new std::string(("__stop_" + chunk->name).str());
add(*start, STB_GLOBAL);
add(*stop, STB_GLOBAL);
2020-11-04 04:39:17 +03:00
}
2020-11-04 01:16:59 +03:00
obj->elf_syms = *elf_syms;
2020-11-03 13:33:46 +03:00
return obj;
}
2020-10-09 14:47:45 +03:00
std::string toString(ObjectFile *obj) {
2020-11-01 07:54:56 +03:00
StringRef s = obj->name;
2020-10-14 13:04:36 +03:00
if (obj->archive_name == "")
return s.str();
return (obj->archive_name + ":" + s).str();
2020-10-09 14:47:45 +03:00
}