1
1
mirror of https://github.com/rui314/mold.git synced 2024-11-13 09:39:13 +03:00

temporary

This commit is contained in:
Rui Ueyama 2021-01-20 20:47:15 +09:00
parent f902d8b234
commit 28b9a4795b
3 changed files with 86 additions and 49 deletions

20
mold.h
View File

@ -649,6 +649,13 @@ private:
};
struct EhReloc {
bool operator==(const EhReloc &other) const {
return sym == other.sym ||
r_type == other.r_type ||
offset == other.offset ||
r_addend == other.r_addend;
}
Symbol *sym;
u32 r_type;
u32 offset;
@ -658,7 +665,7 @@ struct EhReloc {
struct FdeRecord {
std::string_view contents;
std::vector<EhReloc> rels;
u32 offset = -1;
u32 output_offset = -1;
bool is_alive() const {
if (!rels.empty())
@ -670,15 +677,13 @@ struct FdeRecord {
};
struct CieRecord {
bool operator<(const CieRecord &other) const;
bool operator==(const CieRecord &other) const;
bool operator!=(const CieRecord &other) const;
bool should_merge(const CieRecord &other) const;
std::string_view contents;
std::vector<EhReloc> rels;
std::vector<FdeRecord> fdes;
u32 offset = -1;
u32 output_offset = -1;
u32 leader_offset = -1;
u32 fde_offset = -1;
u32 fde_size = -1;
@ -696,6 +701,8 @@ public:
void construct();
void copy_buf() override;
static u64 get_addr(const Symbol &sym);
private:
std::vector<CieRecord *> cies;
};
@ -1095,6 +1102,9 @@ inline u64 Symbol::get_addr() const {
return out::copyrel->shdr.sh_addr + value;
if (input_section) {
if (input_section->is_ehframe)
return EhFrameSection::get_addr(*this);
if (!input_section->is_alive) {
// The control can reach here if there's a relocation that refers
// a local symbol belonging to a comdat group section. This is a

View File

@ -200,8 +200,14 @@ void ObjectFile::read_ehframe(InputSection &isec) {
std::span<ElfRela> rels = isec.rels;
std::string_view data = get_string(isec.shdr);
const char *begin = data.data();
std::unordered_map<u32, CieRecord *> offset_to_cie;
CieRecord *cur_cie = nullptr;
if (data.empty()) {
cies.push_back({data});
return;
}
std::unordered_map<u32, u32> offset_to_cie;
u32 cur_cie = -1;
u32 cur_cie_offset = -1;
for (ElfRela rel : rels)
@ -214,7 +220,7 @@ void ObjectFile::read_ehframe(InputSection &isec) {
if (size == 0) {
if (data.size() != 4)
Fatal() << *isec.file << ": .eh_frame: garbage at end of section";
cies.push_back({data, {}, {}});
cies.push_back({data});
return;
}
@ -239,21 +245,20 @@ void ObjectFile::read_ehframe(InputSection &isec) {
u32 id = *(u32 *)(contents.data() + 4);
if (id == 0) {
// CIE
cies.push_back({contents, std::move(eh_rels), {}});
offset_to_cie[begin_offset] = &cies.back();
cur_cie = &cies.back();
cur_cie_offset = begin_offset;
cur_cie = cies.size();
offset_to_cie[begin_offset] = cies.size();
cies.push_back({contents, std::move(eh_rels)});
} else {
// FDE
u32 cie_offset = begin_offset + 4 - id;
if (cie_offset != cur_cie_offset) {
auto it = offset_to_cie.find(cie_offset);
assert(it != offset_to_cie.end());
cur_cie_offset = it->first;
if (it == offset_to_cie.end())
Fatal() << *isec.file << ": .eh_frame: bad FDE pointer";
cur_cie = it->second;
cur_cie_offset = cie_offset;
}
cur_cie->fdes.push_back({contents, std::move(eh_rels)});
cies[cur_cie].fdes.push_back({contents, std::move(eh_rels)});
}
}
}
@ -878,24 +883,3 @@ std::span<Symbol *> SharedFile::find_aliases(Symbol *sym) {
[&](Symbol *a, Symbol *b) { return a->value < b->value; });
return {begin, end};
}
bool CieRecord::operator<(const CieRecord &other) const {
if (contents < other.contents)
return true;
if (rels.size() != other.rels.size())
return rels.size() < other.rels.size();
for (int i = 0; i < rels.size() && i < other.rels.size(); i++) {
if (rels[i].sym < other.rels[i].sym ||
rels[i].offset < other.rels[i].offset)
return true;
}
return false;
}
bool CieRecord::operator==(const CieRecord &other) const {
return !(*this < other) && !(other < *this);
}
bool CieRecord::operator!=(const CieRecord &other) const {
return !(*this == other);
}

View File

@ -700,7 +700,6 @@ void MergedSection::copy_buf() {
});
}
void EhFrameSection::construct() {
// Remove dead FDEs and assign them offsets within their corresponding
// CIE group.
@ -711,7 +710,7 @@ void EhFrameSection::construct() {
for (FdeRecord &fde : cie.fdes) {
if (!fde.is_alive())
continue;
fde.offset = offset;
fde.output_offset = offset;
offset += fde.contents.size();
}
cie.fde_size = offset;
@ -724,15 +723,17 @@ void EhFrameSection::construct() {
for (CieRecord &cie : file->cies)
cies.push_back(&cie);
sort(cies, [](CieRecord *a, CieRecord *b) { return *a < *b; });
// Assign offsets within the output section to CIEs.
auto should_merge = [](CieRecord &a, CieRecord &b) {
return a.contents == b.contents && a.rels == b.rels;
};
u32 offset = 0;
for (int i = 0; i < cies.size(); i++) {
CieRecord &cie = *cies[i];
cie.offset = offset;
cie.output_offset = offset;
if (i == 0 || cie != *cies[i - 1]) {
if (i == 0 || !should_merge(cie, *cies[i - 1])) {
cie.leader_offset = offset;
offset += cie.contents.size() + cie.fde_size;
} else {
@ -760,14 +761,16 @@ void EhFrameSection::copy_buf() {
u32 cie_size = 0;
// Copy a CIE.
if (cie->offset == cie->leader_offset) {
memcpy(base + cie->offset, cie->contents.data(), cie->contents.size());
if (cie->output_offset == cie->leader_offset) {
memcpy(base + cie->output_offset, cie->contents.data(),
cie->contents.size());
cie_size = cie->contents.size();
for (EhReloc &rel : cie->rels) {
u32 S = rel.sym->get_addr();
u32 P = shdr.sh_addr + cie->offset + rel.offset;
apply_reloc(rel, base + cie->offset + rel.offset, S, P, rel.r_addend);
u32 P = shdr.sh_addr + cie->output_offset + rel.offset;
u8 *loc = base + cie->output_offset + rel.offset;
apply_reloc(rel, loc, S, P, rel.r_addend);
}
}
@ -776,19 +779,59 @@ void EhFrameSection::copy_buf() {
if (!fde.is_alive())
continue;
u32 fde_off = cie->offset + cie_size + fde.offset;
u32 fde_off = cie->output_offset + cie_size + fde.output_offset;
memcpy(base + fde_off, fde.contents.data(), fde.contents.size());
*(u32 *)(base + fde_off + 4) = fde_off + 4 - cie->leader_offset;
for (EhReloc &rel : fde.rels) {
u32 S = rel.sym->get_addr();
u32 P = shdr.sh_addr + fde_off + rel.offset;
apply_reloc(rel, base + fde_off + rel.offset, S, P, rel.r_addend);
u8 *loc = base + fde_off + rel.offset;
apply_reloc(rel, loc, S, P, rel.r_addend);
}
}
});
}
u64 EhFrameSection::get_addr(const Symbol &sym) {
InputSection &isec = *sym.input_section;
ObjectFile &file = *isec.file;
const char *section_begin = file.get_string(isec.shdr).data();
auto contains = [](std::string_view str, const char *ptr) {
const char *begin = str.data();
const char *end = begin + str.size();
return (begin == ptr) || (begin < ptr && ptr < end);
};
for (CieRecord &cie : file.cies) {
u64 offset = 0;
if (cie.output_offset == cie.leader_offset) {
if (contains(cie.contents, section_begin + offset)) {
u64 cie_addr = out::ehframe->shdr.sh_addr + cie.output_offset;
u64 addend = sym.value - offset;
return cie_addr + addend;
}
offset += cie.contents.size();
}
for (FdeRecord &fde : cie.fdes) {
if (contains(fde.contents, section_begin + offset)) {
if (!fde.is_alive())
return 0;
u64 fde_addr = out::ehframe->shdr.sh_addr + cie.output_offset + offset;
u64 addend = sym.value - offset;
return fde_addr + addend;
}
offset += fde.contents.size();
}
}
Fatal() << file << ": .eh_frame has bad symbol: " << sym.name;
}
void CopyrelSection::add_symbol(Symbol *sym) {
assert(sym->is_imported);
if (sym->has_copyrel)