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

Move target-independent files to the top directory

This commit is contained in:
Rui Ueyama 2021-09-08 19:49:51 +09:00
parent 8f10ac5047
commit 78bddacd5b
9 changed files with 291 additions and 297 deletions

View File

@ -17,7 +17,7 @@
#include <tbb/parallel_for_each.h>
#include <zlib.h>
namespace mold::elf {
namespace mold {
static constexpr i64 SHARD_SIZE = 1024 * 1024;
@ -41,7 +41,7 @@ static std::vector<u8> do_compress(std::string_view input) {
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
int r = deflateInit2(&strm, 3, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
ASSERT(r == Z_OK);
assert(r == Z_OK);
// Set an input buffer
strm.avail_in = input.size();
@ -55,8 +55,8 @@ static std::vector<u8> do_compress(std::string_view input) {
strm.next_out = buf.data();
r = deflate(&strm, Z_SYNC_FLUSH);
ASSERT(r == Z_OK);
ASSERT(strm.avail_out > 0);
assert(r == Z_OK);
assert(strm.avail_out > 0);
buf.resize(buf.size() - strm.avail_out);
deflateEnd(&strm);
@ -163,4 +163,4 @@ void GzipCompressor::write_to(u8 *buf) {
*(u32 *)(end - 4) = uncompressed_size;
}
} // namespace mold::elf
} // namespace mold

View File

@ -1,83 +0,0 @@
#include "mold.h"
namespace mold::elf {
static const char *locked = (char *)-1;
template <typename T>
ConcurrentMap<T>::ConcurrentMap() {}
template <typename T>
ConcurrentMap<T>::ConcurrentMap(i64 nbuckets) {
resize(nbuckets);
}
template <typename T>
void ConcurrentMap<T>::resize(i64 nbuckets) {
this->~ConcurrentMap();
nbuckets = std::max<i64>(MIN_NBUCKETS, next_power_of_two(nbuckets));
this->nbuckets = nbuckets;
keys = (std::atomic<const char *> *)calloc(nbuckets, sizeof(keys[0]));
sizes = (u32 *)calloc(nbuckets, sizeof(sizes[0]));
values = (T *)calloc(nbuckets, sizeof(values[0]));
}
template <typename T>
ConcurrentMap<T>::~ConcurrentMap() {
if (keys) {
free((void *)keys);
free((void *)sizes);
free((void *)values);
}
}
template <typename T>
std::pair<T *, bool>
ConcurrentMap<T>::insert(std::string_view key, u64 hash, const T &val) {
if (!keys)
return {nullptr, false};
ASSERT(__builtin_popcount(nbuckets) == 1);
i64 idx = hash & (nbuckets - 1);
i64 retry = 0;
while (retry < MAX_RETRY) {
const char *ptr = keys[idx];
if (ptr == locked) {
#ifdef __x86_64__
asm volatile("pause" ::: "memory");
#endif
continue;
}
if (ptr == nullptr) {
if (!keys[idx].compare_exchange_weak(ptr, locked))
continue;
new (values + idx) T(val);
sizes[idx] = key.size();
keys[idx] = key.data();
return {values + idx, true};
}
if (key.size() == sizes[idx] && memcmp(ptr, key.data(), sizes[idx]) == 0)
return {values + idx, false};
u64 mask = nbuckets / NUM_SHARDS - 1;
idx = (idx & ~mask) | ((idx + 1) & mask);
retry++;
}
ASSERT(false && "ConcurrentMap is full");
return {nullptr, false};
}
#define INSTANTIATE(E) \
template class ConcurrentMap<SectionFragment<E>>;
INSTANTIATE(X86_64);
INSTANTIATE(I386);
INSTANTIATE(AARCH64);
} // namespace mold::elf

View File

@ -5,6 +5,7 @@
#endif
#include "elf.h"
#include "../mold.h"
#include <atomic>
#include <cassert>
@ -44,16 +45,6 @@ template<> struct tbb::tbb_hash_compare<std::string_view> {
namespace mold::elf {
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
static constexpr i32 SECTOR_SIZE = 512;
static constexpr i32 COMMON_PAGE_SIZE = 4096;
static constexpr i32 SHA256_SIZE = 32;
@ -77,12 +68,6 @@ template <typename E> class ROutputShdr;
template <typename E> class RStrtabSection;
template <typename E> class RSymtabSection;
template <typename T> class ConcurrentMap;
class ZlibCompressor;
class GzipCompressor;
class TarFile;
template <typename E> void cleanup();
template <typename E>
@ -301,63 +286,6 @@ private:
void report_undef(Context<E> &ctx, Symbol<E> &sym);
};
//
// hyperloglog.cc
//
class HyperLogLog {
public:
HyperLogLog() : buckets(NBUCKETS) {}
void insert(u32 hash) {
merge_one(hash & (NBUCKETS - 1), __builtin_clz(hash) + 1);
}
void merge_one(i64 idx, u8 newval) {
u8 cur = buckets[idx];
while (cur < newval)
if (buckets[idx].compare_exchange_strong(cur, newval))
break;
}
i64 get_cardinality() const;
void merge(const HyperLogLog &other);
private:
static constexpr i64 NBUCKETS = 2048;
static constexpr double ALPHA = 0.79402;
std::vector<std::atomic_uint8_t> buckets;
};
//
// concurrent-map.cc
//
template <typename T>
class ConcurrentMap {
public:
ConcurrentMap();
ConcurrentMap(i64 nbuckets);
~ConcurrentMap();
void resize(i64 nbuckets);
std::pair<T *, bool> insert(std::string_view key, u64 hash, const T &val);
bool has_key(i64 idx) {
return keys[idx];
}
static constexpr i64 MIN_NBUCKETS = 2048;
static constexpr i64 NUM_SHARDS = 16;
static constexpr i64 MAX_RETRY = 128;
i64 nbuckets = 0;
std::atomic<const char *> *keys = nullptr;
u32 *sizes = nullptr;
T *values = nullptr;
};
//
// output-chunks.cc
//
@ -1171,18 +1099,6 @@ protected:
: path(path), filesize(filesize), is_mmapped(is_mmapped) {}
};
//
// filepath.cc
//
// These are various utility functions to deal with file pathnames.
std::string get_current_dir();
std::string_view path_dirname(std::string_view path);
std::string_view path_filename(std::string_view path);
std::string_view path_basename(std::string_view path);
std::string path_to_absolute(std::string_view path);
std::string path_clean(std::string_view path);
//
// perf.cc
//
@ -1318,59 +1234,6 @@ template <typename E>
void parse_nonpositional_args(Context<E> &ctx,
std::vector<std::string_view> &remaining);
//
// compress.cc
//
class ZlibCompressor {
public:
ZlibCompressor(std::string_view input);
void write_to(u8 *buf);
i64 size() const;
private:
std::vector<std::vector<u8>> shards;
u64 checksum = 0;
};
class GzipCompressor {
public:
GzipCompressor(std::string_view input);
void write_to(u8 *buf);
i64 size() const;
private:
std::vector<std::vector<u8>> shards;
u32 checksum = 0;
u32 uncompressed_size = 0;
};
//
// tar.cc
//
// TarFile is a class to create a tar file.
//
// If you pass `--reproduce=repro.tar` to mold, mold collects all
// input files and put them into `repro.tar`, so that it is easy to
// run the same command with the same command line arguments.
class TarFile {
public:
static constexpr i64 BLOCK_SIZE = 512;
TarFile(std::string basedir) : basedir(basedir) {}
void append(std::string path, std::string_view data);
void write_to(u8 *buf);
i64 size() const { return size_; }
private:
std::string basedir;
std::vector<std::pair<std::string, std::string_view>> contents;
i64 size_ = BLOCK_SIZE * 2;
};
//
// passes.cc
//
@ -2123,21 +1986,6 @@ operator<<(std::ostream &out, const InputSection<E> &isec) {
return out;
}
inline u64 align_to(u64 val, u64 align) {
if (align == 0)
return val;
ASSERT(__builtin_popcount(align) == 1);
return (val + align - 1) & ~(align - 1);
}
inline u64 next_power_of_two(u64 val) {
ASSERT(val >> 63 == 0);
if (val == 0 || val == 1)
return 1;
return (u64)1 << (64 - __builtin_clzl(val - 1));
}
template <typename E>
inline u64 SectionFragment<E>::get_addr(Context<E> &ctx) const {
return output_section.shdr.sh_addr + offset;
@ -2306,52 +2154,4 @@ inline void write_vector(u8 *buf, const std::vector<T> &vec) {
memcpy(buf, vec.data(), vec.size() * sizeof(T));
}
template <typename T, typename U>
inline void append(std::vector<T> &vec1, std::vector<U> vec2) {
vec1.insert(vec1.end(), vec2.begin(), vec2.end());
}
template <typename T>
inline std::vector<T> flatten(std::vector<std::vector<T>> &vec) {
std::vector<T> ret;
for (std::vector<T> &v : vec)
append(ret, v);
return ret;
}
template <typename T, typename U>
inline void erase(std::vector<T> &vec, U pred) {
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}
template <typename T, typename U>
inline void sort(T &vec, U less) {
std::stable_sort(vec.begin(), vec.end(), less);
}
inline u64 read64be(u8 *buf) {
return ((u64)buf[0] << 56) | ((u64)buf[1] << 48) |
((u64)buf[2] << 40) | ((u64)buf[3] << 32) |
((u64)buf[4] << 24) | ((u64)buf[5] << 16) |
((u64)buf[6] << 8) | (u64)buf[7];
}
inline void write64be(u8 *buf, u64 val) {
buf[0] = val >> 56;
buf[1] = val >> 48;
buf[2] = val >> 40;
buf[3] = val >> 32;
buf[4] = val >> 24;
buf[5] = val >> 16;
buf[6] = val >> 8;
buf[7] = val;
}
inline void write32be(u8 *buf, u32 val) {
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
}
} // namespace mold::elf

View File

@ -1,6 +1,6 @@
#include "mold.h"
namespace mold::elf {
namespace mold {
std::string get_current_dir() {
std::string buf(8192, '\0');
@ -106,4 +106,4 @@ std::string path_clean(std::string_view path) {
return ret;
}
} // namespace mold::elf
} // namespace mold

View File

@ -8,7 +8,7 @@
#include <cmath>
namespace mold::elf {
namespace mold {
i64 HyperLogLog::get_cardinality() const {
double z = 0;
@ -22,4 +22,4 @@ void HyperLogLog::merge(const HyperLogLog &other) {
merge_one(i, other.buckets[i]);
}
} // namespace mold::elf
} // namespace mold

View File

@ -1,3 +1,5 @@
#include "../mold.h"
namespace mold::macho {
int macho_main(int argc, char **argv);

View File

@ -2,7 +2,7 @@
#include "macho/mold.h"
int main(int argc, char **argv) {
std::string_view cmd = mold::elf::path_filename(argv[0]);
std::string_view cmd = mold::path_filename(argv[0]);
if (cmd == "ld" || cmd == "mold" || cmd == "ld.mold")
return mold::elf::elf_main<mold::elf::X86_64>(argc, argv);

275
mold.h Normal file
View File

@ -0,0 +1,275 @@
#pragma once
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <atomic>
#include <cassert>
#include <cstring>
#include <span>
#include <string>
#include <string_view>
#include <unistd.h>
#include <vector>
namespace mold {
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
//
// Inline functions
//
inline u64 align_to(u64 val, u64 align) {
if (align == 0)
return val;
assert(__builtin_popcount(align) == 1);
return (val + align - 1) & ~(align - 1);
}
inline u64 next_power_of_two(u64 val) {
assert(val >> 63 == 0);
if (val == 0 || val == 1)
return 1;
return (u64)1 << (64 - __builtin_clzl(val - 1));
}
template <typename T, typename U>
inline void append(std::vector<T> &vec1, std::vector<U> vec2) {
vec1.insert(vec1.end(), vec2.begin(), vec2.end());
}
template <typename T>
inline std::vector<T> flatten(std::vector<std::vector<T>> &vec) {
std::vector<T> ret;
for (std::vector<T> &v : vec)
append(ret, v);
return ret;
}
template <typename T, typename U>
inline void erase(std::vector<T> &vec, U pred) {
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}
template <typename T, typename U>
inline void sort(T &vec, U less) {
std::stable_sort(vec.begin(), vec.end(), less);
}
inline u64 read64be(u8 *buf) {
return ((u64)buf[0] << 56) | ((u64)buf[1] << 48) |
((u64)buf[2] << 40) | ((u64)buf[3] << 32) |
((u64)buf[4] << 24) | ((u64)buf[5] << 16) |
((u64)buf[6] << 8) | (u64)buf[7];
}
inline void write64be(u8 *buf, u64 val) {
buf[0] = val >> 56;
buf[1] = val >> 48;
buf[2] = val >> 40;
buf[3] = val >> 32;
buf[4] = val >> 24;
buf[5] = val >> 16;
buf[6] = val >> 8;
buf[7] = val;
}
inline void write32be(u8 *buf, u32 val) {
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
}
//
// Concurrent Map
//
template <typename T>
class ConcurrentMap {
public:
ConcurrentMap() {}
ConcurrentMap(i64 nbuckets) {
resize(nbuckets);
}
~ConcurrentMap() {
if (keys) {
free((void *)keys);
free((void *)sizes);
free((void *)values);
}
}
void resize(i64 nbuckets) {
this->~ConcurrentMap();
nbuckets = std::max<i64>(MIN_NBUCKETS, next_power_of_two(nbuckets));
this->nbuckets = nbuckets;
keys = (std::atomic<const char *> *)calloc(nbuckets, sizeof(keys[0]));
sizes = (u32 *)calloc(nbuckets, sizeof(sizes[0]));
values = (T *)calloc(nbuckets, sizeof(values[0]));
}
std::pair<T *, bool> insert(std::string_view key, u64 hash, const T &val) {
if (!keys)
return {nullptr, false};
assert(__builtin_popcount(nbuckets) == 1);
i64 idx = hash & (nbuckets - 1);
i64 retry = 0;
while (retry < MAX_RETRY) {
const char *ptr = keys[idx];
if (ptr == locked) {
#ifdef __x86_64__
asm volatile("pause" ::: "memory");
#endif
continue;
}
if (ptr == nullptr) {
if (!keys[idx].compare_exchange_weak(ptr, locked))
continue;
new (values + idx) T(val);
sizes[idx] = key.size();
keys[idx] = key.data();
return {values + idx, true};
}
if (key.size() == sizes[idx] && memcmp(ptr, key.data(), sizes[idx]) == 0)
return {values + idx, false};
u64 mask = nbuckets / NUM_SHARDS - 1;
idx = (idx & ~mask) | ((idx + 1) & mask);
retry++;
}
assert(false && "ConcurrentMap is full");
return {nullptr, false};
}
bool has_key(i64 idx) {
return keys[idx];
}
static constexpr i64 MIN_NBUCKETS = 2048;
static constexpr i64 NUM_SHARDS = 16;
static constexpr i64 MAX_RETRY = 128;
i64 nbuckets = 0;
std::atomic<const char *> *keys = nullptr;
u32 *sizes = nullptr;
T *values = nullptr;
private:
static constexpr const char *locked = "marker";
};
//
// hyperloglog.cc
//
class HyperLogLog {
public:
HyperLogLog() : buckets(NBUCKETS) {}
void insert(u32 hash) {
merge_one(hash & (NBUCKETS - 1), __builtin_clz(hash) + 1);
}
void merge_one(i64 idx, u8 newval) {
u8 cur = buckets[idx];
while (cur < newval)
if (buckets[idx].compare_exchange_strong(cur, newval))
break;
}
i64 get_cardinality() const;
void merge(const HyperLogLog &other);
private:
static constexpr i64 NBUCKETS = 2048;
static constexpr double ALPHA = 0.79402;
std::vector<std::atomic_uint8_t> buckets;
};
//
// filepath.cc
//
// These are various utility functions to deal with file pathnames.
std::string get_current_dir();
std::string_view path_dirname(std::string_view path);
std::string_view path_filename(std::string_view path);
std::string_view path_basename(std::string_view path);
std::string path_to_absolute(std::string_view path);
std::string path_clean(std::string_view path);
//
// compress.cc
//
class ZlibCompressor {
public:
ZlibCompressor(std::string_view input);
void write_to(u8 *buf);
i64 size() const;
private:
std::vector<std::vector<u8>> shards;
u64 checksum = 0;
};
class GzipCompressor {
public:
GzipCompressor(std::string_view input);
void write_to(u8 *buf);
i64 size() const;
private:
std::vector<std::vector<u8>> shards;
u32 checksum = 0;
u32 uncompressed_size = 0;
};
//
// tar.cc
//
// TarFile is a class to create a tar file.
//
// If you pass `--reproduce=repro.tar` to mold, mold collects all
// input files and put them into `repro.tar`, so that it is easy to
// run the same command with the same command line arguments.
class TarFile {
public:
static constexpr i64 BLOCK_SIZE = 512;
TarFile(std::string basedir) : basedir(basedir) {}
void append(std::string path, std::string_view data);
void write_to(u8 *buf);
i64 size() const { return size_; }
private:
std::string basedir;
std::vector<std::pair<std::string, std::string_view>> contents;
i64 size_ = BLOCK_SIZE * 2;
};
} // namespace mold

View File

@ -1,6 +1,6 @@
#include "mold.h"
namespace mold::elf {
namespace mold {
// A tar file consists of one or more Ustar header followed by data.
// Each Ustar header represents a single file in an archive.
@ -67,7 +67,7 @@ void TarFile::write_to(u8 *buf) {
memset(buf, 0, size_);
for (i64 i = 0; i < contents.size(); i++) {
ASSERT(buf - start <= size_);
assert(buf - start <= size_);
const std::string &path = contents[i].first;
std::string_view data = contents[i].second;
@ -99,4 +99,4 @@ void TarFile::write_to(u8 *buf) {
}
}
} // namespace mold::elf
} // namespace mold