mirror of
https://github.com/rui314/mold.git
synced 2024-11-13 09:39:13 +03:00
temporary
This commit is contained in:
parent
f902d8b234
commit
28b9a4795b
20
mold.h
20
mold.h
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user