1
1
mirror of https://github.com/rui314/mold.git synced 2024-12-27 10:23:41 +03:00
This commit is contained in:
Rui Ueyama 2021-03-11 17:06:43 +09:00
parent 25200eb61c
commit c074f8ade6
4 changed files with 78 additions and 91 deletions

43
main.cc
View File

@ -351,48 +351,9 @@ static void eliminate_comdats() {
static void handle_mergeable_strings() {
Timer t("handle_mergeable_strings");
// Resolve mergeable string fragments
tbb::parallel_for_each(out::objs, [](ObjectFile *file) {
for (MergeableSection *isec : file->mergeable_sections) {
for (SectionFragment *frag : isec->fragments) {
if (!frag->is_alive)
continue;
MergeableSection *cur = frag->isec;
while (!cur || cur->file->priority > isec->file->priority)
if (frag->isec.compare_exchange_weak(cur, isec))
break;
}
}
tbb::parallel_for_each(MergedSection::instances, [](MergedSection *sec) {
sec->assign_offsets();
});
// Calculate the total bytes of mergeable strings for each input section.
tbb::parallel_for_each(out::objs, [](ObjectFile *file) {
for (MergeableSection *isec : file->mergeable_sections) {
i64 offset = 0;
for (SectionFragment *frag : isec->fragments) {
if (frag->isec == isec && frag->offset == -1) {
offset = align_to(offset, frag->alignment);
frag->offset = offset;
offset += frag->data.size();
isec->alignment = std::max<u32>(isec->alignment, frag->alignment);
}
}
isec->size = offset;
}
});
// Assign each mergeable input section a unique index.
for (ObjectFile *file : out::objs) {
for (MergeableSection *isec : file->mergeable_sections) {
i64 offset = isec->parent.shdr.sh_size;
isec->padding = align_to(offset, isec->alignment) - offset;
isec->offset = offset + isec->padding;
isec->parent.shdr.sh_size = offset + isec->padding + isec->size;
isec->parent.shdr.sh_addralign =
std::max(isec->parent.shdr.sh_addralign, isec->shdr->sh_addralign);
}
}
}
// So far, each input section has a pointer to its corresponding

43
mold.h
View File

@ -209,14 +209,17 @@ public:
//
struct SectionFragment {
SectionFragment(std::string_view data) : data(data) {}
SectionFragment(MergedSection *sec, std::string_view data)
: output_section(*sec), data(data) {}
SectionFragment(const SectionFragment &other)
: isec(other.isec.load()), data(other.data), offset(other.offset) {}
: output_section(other.output_section), data(other.data),
offset(other.offset), alignment(other.alignment.load()),
is_alive(other.is_alive.load()) {}
inline u64 get_addr() const;
std::atomic<MergeableSection *> isec = nullptr;
MergedSection &output_section;
std::string_view data;
u32 offset = -1;
std::atomic_uint16_t alignment = 1;
@ -435,7 +438,6 @@ public:
MergedSection &parent;
std::vector<SectionFragment *> fragments;
std::vector<u32> frag_offsets;
u32 alignment = 1;
u32 size = 0;
u32 padding = 0;
};
@ -752,27 +754,19 @@ public:
class MergedSection : public OutputChunk {
public:
static MergedSection *get_instance(std::string_view name, u64 type, u64 flags);
static MergedSection *
get_instance(std::string_view name, u64 type, u64 flags);
SectionFragment *insert(std::string_view data, i64 alignment);
void assign_offsets();
void copy_buf() override;
static inline std::vector<MergedSection *> instances;
SectionFragment *insert(std::string_view data, i64 alignment) {
assert(alignment < UINT16_MAX);
typename decltype(map)::const_accessor acc;
map.insert(acc, std::pair(data, SectionFragment(data)));
SectionFragment *frag = const_cast<SectionFragment *>(&acc->second);
u16 cur = frag->alignment;
while (cur < alignment)
if (frag->alignment.compare_exchange_strong(cur, alignment))
break;
return frag;
}
void copy_buf() override;
private:
typedef tbb::concurrent_hash_map<std::string_view, SectionFragment> MapTy;
static constexpr i64 NUM_SHARDS = 32;
MergedSection(std::string_view name, u64 flags, u32 type)
: OutputChunk(SYNTHETIC) {
this->name = name;
@ -780,7 +774,8 @@ private:
shdr.sh_type = type;
}
tbb::concurrent_hash_map<std::string_view, SectionFragment> map;
MapTy maps[NUM_SHARDS];
std::vector<SectionFragment *> fragments;
};
class EhFrameSection : public OutputChunk {
@ -1391,9 +1386,7 @@ inline u64 Symbol::get_plt_addr() const {
inline u64 SectionFragment::get_addr() const {
if (!is_alive)
return 0; // todo: remove
MergeableSection *is = isec.load();
return is->parent.shdr.sh_addr + is->offset + offset;
return output_section.shdr.sh_addr + offset;
}
inline u64 InputChunk::get_addr() const {

View File

@ -794,38 +794,71 @@ MergedSection::get_instance(std::string_view name, u64 type, u64 flags) {
return osec;
}
void MergedSection::copy_buf() {
u8 *base = out::buf + shdr.sh_offset;
SectionFragment *MergedSection::insert(std::string_view data, i64 alignment) {
assert(alignment < UINT16_MAX);
tbb::parallel_for_each(out::objs, [&](ObjectFile *file) {
for (MergeableSection *isec : file->mergeable_sections) {
if (&isec->parent != this)
continue;
std::string_view suffix = data;
if (suffix.size() > 32)
suffix = suffix.substr(suffix.size() - 32);
i64 shard = std::hash<std::string_view>()(suffix) % NUM_SHARDS;
// Clear padding between input sections
if (isec->padding)
memset(base + isec->offset - isec->padding, 0, isec->padding);
MapTy::const_accessor acc;
bool inserted =
maps[shard].insert(acc, std::pair(data, SectionFragment(this, data)));
SectionFragment *frag = const_cast<SectionFragment *>(&acc->second);
i64 offset = 0;
for (SectionFragment *frag : isec->fragments) {
if (frag->isec != isec || !frag->is_alive || frag->offset < offset)
continue;
u16 cur = frag->alignment;
while (cur < alignment)
if (frag->alignment.compare_exchange_strong(cur, alignment))
break;
return frag;
}
// Clear padding between section fragments
if (offset < frag->offset) {
memset(base + isec->offset + offset, 0, frag->offset - offset);
offset = frag->offset;
}
void MergedSection::assign_offsets() {
// Collect live section fragments.
std::vector<std::vector<SectionFragment *>> vec(NUM_SHARDS);
memcpy(base + isec->offset + frag->offset,
frag->data.data(), frag->data.size());
offset += frag->data.size();
}
}
tbb::parallel_for((i64)0, NUM_SHARDS, [&](i64 i) {
MapTy &map = maps[i];
for (auto it = map.begin(); it != map.end(); it++)
if (SectionFragment &frag = it->second; frag.is_alive)
vec[i].push_back(&frag);
std::sort(vec[i].begin(), vec[i].end(),
[&](SectionFragment *a, SectionFragment *b) {
if (a->data.size() != b->data.size())
return a->data.size() < b->data.size();
return a->data < b->data;
});
});
fragments = flatten(vec);
// Assign offsets.
i64 offset = 0;
for (SectionFragment *frag : fragments) {
offset = align_to(offset, frag->alignment);
frag->offset = offset;
offset += frag->data.size();
}
shdr.sh_size = offset;
for (SectionFragment *frag : fragments)
shdr.sh_addralign = std::max<i64>(shdr.sh_addralign, frag->alignment);
}
void MergedSection::copy_buf() {
u8 *base = out::buf + shdr.sh_offset;
i64 n = 0;
for (SectionFragment *frag : fragments) {
memset(base + n, 0, frag->offset - n);
memcpy(base + frag->offset, frag->data.data(), frag->data.size());
n = frag->offset + frag->data.size();
}
static Counter merged_strings("merged_strings");
merged_strings += map.size();
merged_strings += fragments.size();
}
void EhFrameSection::construct() {

View File

@ -17,7 +17,7 @@ clang -shared -fuse-ld=`pwd`/../mold -o $t/b.so $t/a.o
readelf --dyn-syms $t/b.so > $t/log
grep -q '0000000000000000 0 NOTYPE GLOBAL DEFAULT UND fn2' $t/log
grep -q '000000000000111c 0 NOTYPE GLOBAL DEFAULT 16 fn1' $t/log
grep -q '000000000000111c 0 NOTYPE GLOBAL DEFAULT 17 fn1' $t/log
cat <<EOF | clang -fPIC -c -o $t/c.o -xc -
#include <stdio.h>