mirror of
https://github.com/rui314/mold.git
synced 2026-11-08 17:48:41 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57f5c77174 | ||
|
|
ac6f1ec18e | ||
|
|
d19f822ec0 | ||
|
|
a97a628ee8 | ||
|
|
2888aade4c | ||
|
|
0172f22ab5 | ||
|
|
418d4ff62a | ||
|
|
5249edc57f | ||
|
|
1870845f88 | ||
|
|
d15c41a8dd | ||
|
|
b7c8a843b2 | ||
|
|
9b77a7ea86 | ||
|
|
af396ad5d9 | ||
|
|
a2ee7371d5 | ||
|
|
c9812cf09f | ||
|
|
e9c070a3c2 | ||
|
|
02e75be9fa | ||
|
|
d5609a9bb8 | ||
|
|
5d24db5a64 | ||
|
|
aeec8baee5 | ||
|
|
b74a771886 | ||
|
|
0124058ef7 | ||
|
|
e302a2509c | ||
|
|
f70db66373 | ||
|
|
9c0cbc8e6c | ||
|
|
a9acbd6b6f | ||
|
|
b9d65a5787 | ||
|
|
50766f1ad4 | ||
|
|
3496ad1291 | ||
|
|
8a3d374251 | ||
|
|
96b2710849 | ||
|
|
a43f3953f0 | ||
|
|
2bc6ddc41c | ||
|
|
f6575d53c1 | ||
|
|
bf1ec5ac8f | ||
|
|
b291100cfe | ||
|
|
c43a859a90 | ||
|
|
6e3d0e3a3c | ||
|
|
790ce3f64d | ||
|
|
cbd7f74c2e | ||
|
|
3fe25fc69d | ||
|
|
823ef09585 | ||
|
|
f20f57060a | ||
|
|
0061d53409 | ||
|
|
82affb94d8 | ||
|
|
4f782fb7dc | ||
|
|
e9eb6020a6 | ||
|
|
23a662cbb9 |
No files matched your search
@@ -70,6 +70,7 @@ jobs:
|
||||
- gentoo/stage3
|
||||
- opensuse/tumbleweed
|
||||
- ubuntu:22.04
|
||||
- ubuntu:25.04
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ matrix.distro }}
|
||||
steps:
|
||||
|
||||
@@ -5,7 +5,7 @@ apt-get install -y wget xz-utils
|
||||
|
||||
# Install a 32-bit RISC-V toolchain
|
||||
mkdir /rv32
|
||||
wget -O- -q https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2023.07.07/riscv32-glibc-ubuntu-20.04-gcc-nightly-2023.07.07-nightly.tar.gz | tar -C /rv32 --strip-components=1 -xzf -
|
||||
wget -O- -q https://github.com/riscv-collab/riscv-gnu-toolchain/releases/download/2025.01.20/riscv32-glibc-ubuntu-22.04-gcc-nightly-2025.01.20-nightly.tar.xz | tar -C /rv32 --strip-components=1 --xz -xf -
|
||||
|
||||
ln -sf /rv32/sysroot /usr/riscv32-linux-gnu
|
||||
echo '/rv32/bin/riscv32-unknown-linux-gnu-gcc -L/usr/riscv32-linux-gnu "$@"' > /usr/bin/riscv32-linux-gnu-gcc
|
||||
|
||||
+2
-1
@@ -311,7 +311,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
# on a multicore machine.
|
||||
list(APPEND MOLD_ELF_TARGETS
|
||||
X86_64 I386 ARM64LE ARM64BE ARM32 RV32LE RV32BE RV64LE RV64BE PPC32
|
||||
PPC64V1 PPC64V2 S390X SPARC64 M68K SH4LE SH4BE LOONGARCH32 LOONGARCH64)
|
||||
PPC64V1 PPC64V2 S390X SPARC64 M68K SH4LE SH4BE LOONGARCH32 LOONGARCH64 ARC)
|
||||
|
||||
list(APPEND MOLD_ELF_TEMPLATE_FILES
|
||||
src/arch-arm64.cc
|
||||
@@ -385,6 +385,7 @@ target_sources(mold PRIVATE
|
||||
lib/perf.cc
|
||||
lib/random.cc
|
||||
lib/tar.cc
|
||||
src/arch-arc.cc
|
||||
src/arch-arm32.cc
|
||||
src/arch-i386.cc
|
||||
src/arch-m68k.cc
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash -x
|
||||
set -e
|
||||
apt-get install -y git bzip2 ninja-build pkg-config libglib2.0-dev python3-distutils-extra libpixman-1-dev
|
||||
|
||||
cd /
|
||||
git clone --depth=1 https://github.com/foss-for-synopsys-dwc-arc-processors/qemu.git
|
||||
mkdir /qemu/build
|
||||
cd /qemu/build
|
||||
../configure --static --extra-cflags=-Wno-error
|
||||
ninja
|
||||
ln -s /qemu/build/qemu-arc /qemu/build/qemu-arc64 /usr/local/bin
|
||||
|
||||
|
||||
apt-get install -y libgmp-dev libmpfr-dev texinfo bison yacc flex
|
||||
cd /
|
||||
git clone --depth=1 https://github.com/foss-for-synopsys-dwc-arc-processors/binutils-gdb.git
|
||||
cd /binutils-gdb
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --target=arc-linux
|
||||
make -j$(nproc)
|
||||
|
||||
|
||||
apt-get install -y mold
|
||||
mkdir /build
|
||||
cd /build
|
||||
cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DMOLD_USE_MOLD=1 /mold
|
||||
ninja
|
||||
TRIPLE=arc-linux-gnu bash -x /mold/test/hello-dynamic.sh
|
||||
@@ -10,8 +10,7 @@ set -x
|
||||
case "$ID" in
|
||||
ubuntu | pop | linuxmint | debian | raspbian | neon)
|
||||
apt-get update
|
||||
apt-get install -y cmake gcc g++
|
||||
if [ "$ID-$VERSION_ID" = ubuntu-20.04 ]; then apt-get install -y g++-10; fi
|
||||
apt-get install -y cmake gcc g++ clang gdb
|
||||
;;
|
||||
fedora | amzn | rhel | centos)
|
||||
dnf install -y gcc-g++ cmake glibc-static libstdc++-static diffutils util-linux tar
|
||||
|
||||
@@ -11,7 +11,7 @@ set -x
|
||||
|
||||
case "$ID" in
|
||||
ubuntu | pop | linuxmint | debian | raspbian)
|
||||
apt-get install -y qemu-user {gcc,g++}-{i686,aarch64,riscv64,powerpc,powerpc64,powerpc64le,s390x,sparc64,m68k,sh4}-linux-gnu {gcc,g++}-arm-linux-gnueabihf
|
||||
apt-get install -y qemu-user {gcc,g++}-{i686,aarch64,riscv64,powerpc,powerpc64,powerpc64le,s390x,sparc64,m68k,sh4,arc}-linux-gnu {gcc,g++}-arm-linux-gnueabihf
|
||||
;;
|
||||
*)
|
||||
echo "Error: don't know anything about build dependencies on $ID-$VERSION_ID"
|
||||
|
||||
+18
-8
@@ -60,6 +60,7 @@ public:
|
||||
|
||||
namespace mold {
|
||||
|
||||
namespace ranges = std::ranges;
|
||||
using namespace std::literals::string_literals;
|
||||
using namespace std::literals::string_view_literals;
|
||||
|
||||
@@ -416,14 +417,6 @@ inline std::vector<T> flatten(std::vector<std::vector<T>> &vec) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline void sort(auto &vec) {
|
||||
std::stable_sort(vec.begin(), vec.end());
|
||||
}
|
||||
|
||||
inline void sort(auto &vec, auto less) {
|
||||
std::stable_sort(vec.begin(), vec.end(), less);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void remove_duplicates(std::vector<T> &vec) {
|
||||
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
|
||||
@@ -490,6 +483,23 @@ inline u64 read_uleb(u8 *buf) {
|
||||
return read_uleb(&tmp);
|
||||
}
|
||||
|
||||
inline i64 read_sleb(u8 **buf) {
|
||||
u64 val = 0;
|
||||
u8 shift = 0;
|
||||
u8 byte;
|
||||
do {
|
||||
byte = *(*buf)++;
|
||||
val |= (byte & 0x7f) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
return sign_extend(val, shift);
|
||||
}
|
||||
|
||||
inline i64 read_sleb(u8 *buf) {
|
||||
u8 *tmp = buf;
|
||||
return read_sleb(&tmp);
|
||||
}
|
||||
|
||||
inline u64 read_uleb(std::string_view *str) {
|
||||
u8 *start = (u8 *)str->data();
|
||||
u8 *ptr = start;
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ u32 compute_crc32(u32 crc, u8 *buf, i64 len) {
|
||||
len -= sz;
|
||||
}
|
||||
|
||||
tbb::parallel_for_each(shards.begin(), shards.end(), [](Shard &shard) {
|
||||
tbb::parallel_for_each(shards, [](Shard &shard) {
|
||||
shard.crc = crc32(0, shard.buf, shard.len);
|
||||
});
|
||||
|
||||
|
||||
+2
-6
@@ -17,9 +17,7 @@ i64 Counter::get_value() {
|
||||
}
|
||||
|
||||
void Counter::print() {
|
||||
sort(instances, [](Counter *a, Counter *b) {
|
||||
return a->get_value() > b->get_value();
|
||||
});
|
||||
ranges::stable_sort(instances, {}, [](Counter *x) { return x->get_value(); });
|
||||
|
||||
for (Counter *c : instances)
|
||||
std::cout << std::setw(20) << std::right << c->name
|
||||
@@ -80,9 +78,7 @@ static void print_rec(TimerRecord &rec, i64 indent) {
|
||||
std::string(indent * 2, ' ').c_str(),
|
||||
rec.name.c_str());
|
||||
|
||||
sort(rec.children, [](TimerRecord *a, TimerRecord *b) {
|
||||
return a->start < b->start;
|
||||
});
|
||||
ranges::stable_sort(rec.children, {}, &TimerRecord::start);
|
||||
|
||||
for (TimerRecord *child : rec.children)
|
||||
print_rec(*child, indent + 1);
|
||||
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
// r31 is blink. r30 is I believe a scratch register.
|
||||
//
|
||||
// Programs might use one of several branch, jump, and link instructions
|
||||
// to control execution flow through direct and indirect function calls
|
||||
// and branching. For function calling, the conditional branch-and-link
|
||||
// instruction has a maximum branch range of ±1 MiB, and the target
|
||||
// address is 32-bit-aligned. The unconditional branch-and-link format has
|
||||
// a maximum branch range of ±16 MiB.
|
||||
//
|
||||
// https://github.com/foss-for-synopsys-dwc-arc-processors/arc-ABI-manual/blob/master/ARCv2_ABI.pdf
|
||||
|
||||
#include "mold.h"
|
||||
|
||||
namespace mold {
|
||||
|
||||
using E = ARC;
|
||||
|
||||
// An integer-like class for the mixed-endian encoding
|
||||
class M32 {
|
||||
public:
|
||||
operator u32() const {
|
||||
return (buf[1] << 24) | (buf[0] << 16) | (buf[3] << 8) | buf[2];
|
||||
}
|
||||
|
||||
M32 &operator=(u32 x) {
|
||||
buf[0] = x >> 16;
|
||||
buf[1] = x >> 24;
|
||||
buf[2] = x;
|
||||
buf[3] = x >> 8;
|
||||
return *this;
|
||||
}
|
||||
|
||||
M32 &operator&=(u32 x) { return *this = *this & x; }
|
||||
M32 &operator|=(u32 x) { return *this = *this | x; }
|
||||
u8 buf[4];
|
||||
};
|
||||
|
||||
static void write_disp7u(u8 *loc, u32 val) {
|
||||
*(ul16 *)loc |= (bits(val, 6, 3) << 4) | bits(val, 2, 0);
|
||||
}
|
||||
|
||||
static void write_disp9(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= bits(val, 8, 0);
|
||||
}
|
||||
|
||||
static void write_disp9ls(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= (bits(val, 7, 0) << 16) | (bit(val, 8) << 15);
|
||||
}
|
||||
|
||||
static void write_disp9s(u8 *loc, u32 val) {
|
||||
*(ul16 *)loc |= bits(val, 8, 0);
|
||||
}
|
||||
|
||||
static void write_disp10u(u8 *loc, u32 val) {
|
||||
*(ul16 *)loc |= bits(val, 9, 0);
|
||||
}
|
||||
|
||||
static void write_disp13s(u8 *loc, u32 val) {
|
||||
*(ul16 *)loc |= bits(val, 12, 0);
|
||||
}
|
||||
|
||||
static void write_disp21h(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= (bits(val, 10, 1) << 17) | (bits(val, 20, 11) << 6);
|
||||
}
|
||||
|
||||
static void write_disp21w(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= (bits(val, 10, 2) << 18) | (bits(val, 20, 11) << 6);
|
||||
}
|
||||
|
||||
static void write_disp25h(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= (bits(val, 10, 1) << 17) | (bits(val, 20, 11) << 6) |
|
||||
bits(val, 24, 21);
|
||||
}
|
||||
|
||||
static void write_disp25w(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= (bits(val, 10, 2) << 18) | (bits(val, 20, 11) << 6) |
|
||||
bits(val, 24, 21);
|
||||
}
|
||||
|
||||
static void write_disps9(u8 *loc, u32 val) {
|
||||
*(ul16 *)loc |= bits(val, 10, 2);
|
||||
}
|
||||
|
||||
static void write_disps12(u8 *loc, u32 val) {
|
||||
*(M32 *)loc |= (bits(val, 5, 0) << 6) | bits(val, 11, 6);
|
||||
}
|
||||
|
||||
template <>
|
||||
void write_plt_header(Context<E> &ctx, u8 *buf) {
|
||||
static const ul16 insn[] = {
|
||||
0x2730, 0x7f8b, 0, 0, // ld r11, [pcl,0]
|
||||
0x2730, 0x7f8a, 0, 0, // ld r10, [pcl,0]
|
||||
0x2020, 0x0280, // j [r10]
|
||||
0, 0, // (address of GOTPLT)
|
||||
};
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(M32 *)(buf + 4) = ctx.gotplt->shdr.sh_addr - ctx.plt->shdr.sh_addr + 4;
|
||||
*(M32 *)(buf + 12) = ctx.gotplt->shdr.sh_addr - ctx.plt->shdr.sh_addr;
|
||||
*(M32 *)(buf + 20) = ctx.gotplt->shdr.sh_addr;
|
||||
}
|
||||
|
||||
template <>
|
||||
void write_plt_entry(Context<E> &ctx, u8 *buf, Symbol<E> &sym) {
|
||||
static const ul16 insn[] = {
|
||||
0x2730, 0x7f8c, 0, 0, // ld r12, [pcl,0]
|
||||
0x2021, 0x0300, // j.d [r12]
|
||||
0x240a, 0x1fc0, // mov r12,pcl
|
||||
};
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(M32 *)(buf + 4) = sym.get_gotplt_addr(ctx) - sym.get_plt_addr(ctx);
|
||||
}
|
||||
|
||||
template <>
|
||||
void write_pltgot_entry(Context<E> &ctx, u8 *buf, Symbol<E> &sym) {
|
||||
static const ul16 insn[] = {
|
||||
0x2730, 0x7f8c, 0, 0, // ld r12, [pcl,0]
|
||||
0x2021, 0x0300, // j.d [r12]
|
||||
0x240a, 0x1fc0, // mov r12,pcl
|
||||
};
|
||||
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(M32 *)(buf + 4) = sym.get_got_pltgot_addr(ctx) - sym.get_plt_addr(ctx);
|
||||
}
|
||||
|
||||
template <>
|
||||
void EhFrameSection<E>::apply_eh_reloc(Context<E> &ctx, const ElfRel<E> &rel,
|
||||
u64 offset, u64 val) {
|
||||
u8 *loc = ctx.buf + this->shdr.sh_offset + offset;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_NONE:
|
||||
break;
|
||||
case R_ARC_32:
|
||||
*(ul32 *)loc = val;
|
||||
break;
|
||||
case R_ARC_32_PCREL:
|
||||
*(ul32 *)loc = val - this->shdr.sh_addr - offset;
|
||||
break;
|
||||
default:
|
||||
Fatal(ctx) << "unsupported relocation in .eh_frame: " << rel;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
const ElfRel<E> &rel = rels[i];
|
||||
if (rel.r_type == R_NONE)
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_ARC_32:
|
||||
*(ul32 *)loc = S + A;
|
||||
break;
|
||||
case R_ARC_32_ME:
|
||||
*(M32 *)loc = S + A;
|
||||
break;
|
||||
case R_ARC_S25H_PCREL:
|
||||
case R_ARC_S25H_PCREL_PLT:
|
||||
write_disp25h(loc, align_to(S + A - P, 2));
|
||||
break;
|
||||
case R_ARC_S25W_PCREL:
|
||||
case R_ARC_S25W_PCREL_PLT:
|
||||
write_disp25w(loc, align_to(S + A - P, 4));
|
||||
break;
|
||||
case R_ARC_PC32:
|
||||
*(M32 *)loc = S + A - P;
|
||||
break;
|
||||
case R_ARC_32_PCREL:
|
||||
*(ul32 *)loc = S + A - P;
|
||||
break;
|
||||
case R_ARC_GOTPC32:
|
||||
*(M32 *)loc = GOT + G + A - P;
|
||||
break;
|
||||
case R_ARC_TLS_LE_32:
|
||||
*(M32 *)loc = S + A - ctx.tp_addr;
|
||||
break;
|
||||
case R_ARC_TLS_IE_GOT:
|
||||
*(M32 *)loc = sym.get_gottp_addr(ctx) + A - P;
|
||||
break;
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
const ElfRel<E> &rel = rels[i];
|
||||
if (rel.r_type == R_NONE || record_undef_error(ctx, rel))
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_ARC_32:
|
||||
if (std::optional<u64> val = get_tombstone(sym, frag))
|
||||
*(ul32 *)loc = *val;
|
||||
else
|
||||
*(ul32 *)loc = S + A;
|
||||
break;
|
||||
default:
|
||||
Fatal(ctx) << *this << ": invalid relocation for non-allocated sections: "
|
||||
<< rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::scan_relocations(Context<E> &ctx) {
|
||||
assert(shdr().sh_flags & SHF_ALLOC);
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
|
||||
for (i64 i = 0; i < rels.size(); i++) {
|
||||
const ElfRel<E> &rel = rels[i];
|
||||
if (rel.r_type == R_NONE || record_undef_error(ctx, rel))
|
||||
continue;
|
||||
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
|
||||
if (sym.is_ifunc())
|
||||
Error(ctx) << sym << ": GNU ifunc symbol is not supported on m68k";
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_ARC_32:
|
||||
break;
|
||||
case R_ARC_32_ME:
|
||||
scan_absrel(ctx, sym, rel);
|
||||
break;
|
||||
case R_ARC_S25H_PCREL:
|
||||
case R_ARC_S25W_PCREL:
|
||||
case R_ARC_32_PCREL:
|
||||
case R_ARC_PC32:
|
||||
scan_pcrel(ctx, sym, rel);
|
||||
break;
|
||||
case R_ARC_S25H_PCREL_PLT:
|
||||
case R_ARC_S25W_PCREL_PLT:
|
||||
if (sym.is_imported)
|
||||
sym.flags |= NEEDS_PLT;
|
||||
break;
|
||||
case R_ARC_GOTPC32:
|
||||
sym.flags |= NEEDS_GOT;
|
||||
break;
|
||||
case R_ARC_TLS_LE_32:
|
||||
check_tlsle(ctx, sym, rel);
|
||||
break;
|
||||
case R_ARC_TLS_IE_GOT:
|
||||
sym.flags |= NEEDS_GOTTP;
|
||||
break;
|
||||
default:
|
||||
Error(ctx) << *this << ": unknown relocation: " << rel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
u64 get_eflags(Context<E> &ctx) {
|
||||
return 0x406;
|
||||
}
|
||||
|
||||
} // namespace mold
|
||||
+8
-7
@@ -57,6 +57,7 @@ i64 get_addend(u8 *loc, const ElfRel<E> &rel) {
|
||||
case R_ARM_TLS_IE32:
|
||||
case R_ARM_TLS_LE32:
|
||||
case R_ARM_TLS_GOTDESC:
|
||||
case R_ARM_TARGET1:
|
||||
case R_ARM_TARGET2:
|
||||
return (il32)*arm;
|
||||
case R_ARM_THM_JUMP8:
|
||||
@@ -181,6 +182,7 @@ void write_addend(u8 *loc, i64 val, const ElfRel<E> &rel) {
|
||||
case R_ARM_TLS_IE32:
|
||||
case R_ARM_TLS_LE32:
|
||||
case R_ARM_TLS_GOTDESC:
|
||||
case R_ARM_TARGET1:
|
||||
case R_ARM_TARGET2:
|
||||
*(ul32 *)loc = val;
|
||||
break;
|
||||
@@ -295,13 +297,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = get_addend(*this, rel);
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
@@ -309,6 +304,10 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
auto get_thumb_thunk_addr = [&] { return sym.get_thunk_addr(ctx, P); };
|
||||
auto get_arm_thunk_addr = [&] { return sym.get_thunk_addr(ctx, P) + 4; };
|
||||
|
||||
@@ -318,6 +317,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_ARM_ABS32:
|
||||
case R_ARM_TARGET1:
|
||||
break;
|
||||
case R_ARM_REL32:
|
||||
*(ul32 *)loc = S + A - P;
|
||||
@@ -647,6 +647,7 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
|
||||
check_tlsle(ctx, sym, rel);
|
||||
break;
|
||||
case R_ARM_ABS32:
|
||||
case R_ARM_TARGET1:
|
||||
case R_ARM_MOVT_ABS:
|
||||
case R_ARM_THM_MOVT_ABS:
|
||||
case R_ARM_REL32:
|
||||
|
||||
+12
-20
@@ -155,19 +155,16 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_AARCH64_ABS64:
|
||||
break;
|
||||
@@ -292,7 +289,7 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
*(ul32 *)loc |= bits(S + A - P, 20, 2) << 5;
|
||||
break;
|
||||
case R_AARCH64_PREL16:
|
||||
check(S + A - P, -(1LL << 15), 1LL << 15);
|
||||
check(S + A - P, -(1LL << 15), 1LL << 16);
|
||||
*(U16<E> *)loc = S + A - P;
|
||||
break;
|
||||
case R_AARCH64_PREL32:
|
||||
@@ -448,13 +445,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
@@ -462,6 +452,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, val, i, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_AARCH64_ABS64:
|
||||
if (std::optional<u64> val = get_tombstone(sym, frag))
|
||||
@@ -469,12 +463,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
else
|
||||
*(U64<E> *)loc = S + A;
|
||||
break;
|
||||
case R_AARCH64_ABS32: {
|
||||
i64 val = S + A;
|
||||
check(val, 0, 1LL << 32);
|
||||
*(U32<E> *)loc = val;
|
||||
case R_AARCH64_ABS32:
|
||||
check(S + A, 0, 1LL << 32);
|
||||
*(U32<E> *)loc = S + A;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Fatal(ctx) << *this << ": invalid relocation for non-allocated sections: "
|
||||
<< rel;
|
||||
|
||||
+38
-46
@@ -108,25 +108,24 @@ template <>
|
||||
void write_plt_header(Context<E> &ctx, u8 *buf) {
|
||||
if (ctx.arg.pic) {
|
||||
static const u8 insn[] = {
|
||||
0xf3, 0x0f, 0x1e, 0xfb, // endbr32
|
||||
0x51, // push %ecx
|
||||
0x8d, 0x8b, 0, 0, 0, 0, // lea GOTPLT+4(%ebx), %ecx
|
||||
0xff, 0x31, // push (%ecx)
|
||||
0xff, 0x61, 0x04, // jmp *0x4(%ecx)
|
||||
0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ul32 *)(buf + 7) = ctx.gotplt->shdr.sh_addr - ctx.got->shdr.sh_addr + 4;
|
||||
*(ul32 *)(buf + 3) = ctx.gotplt->shdr.sh_addr - ctx.got->shdr.sh_addr + 4;
|
||||
} else {
|
||||
static const u8 insn[] = {
|
||||
0xf3, 0x0f, 0x1e, 0xfb, // endbr32
|
||||
0x51, // push %ecx
|
||||
0xb9, 0, 0, 0, 0, // mov GOTPLT+4, %ecx
|
||||
0xff, 0x31, // push (%ecx)
|
||||
0xff, 0x61, 0x04, // jmp *0x4(%ecx)
|
||||
0xcc, // (padding)
|
||||
0x51, // push %ecx
|
||||
0xb9, 0, 0, 0, 0, // mov GOTPLT+4, %ecx
|
||||
0xff, 0x31, // push (%ecx)
|
||||
0xff, 0x61, 0x04, // jmp *0x4(%ecx)
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ul32 *)(buf + 6) = ctx.gotplt->shdr.sh_addr + 4;
|
||||
*(ul32 *)(buf + 2) = ctx.gotplt->shdr.sh_addr + 4;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,24 +133,22 @@ template <>
|
||||
void write_plt_entry(Context<E> &ctx, u8 *buf, Symbol<E> &sym) {
|
||||
if (ctx.arg.pic) {
|
||||
static const u8 insn[] = {
|
||||
0xf3, 0x0f, 0x1e, 0xfb, // endbr32
|
||||
0xb9, 0, 0, 0, 0, // mov $reloc_offset, %ecx
|
||||
0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
|
||||
0xcc, // (padding)
|
||||
0xb9, 0, 0, 0, 0, // mov $reloc_offset, %ecx
|
||||
0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ul32 *)(buf + 5) = sym.get_plt_idx(ctx) * sizeof(ElfRel<E>);
|
||||
*(ul32 *)(buf + 11) = sym.get_gotplt_addr(ctx) - ctx.got->shdr.sh_addr;
|
||||
*(ul32 *)(buf + 1) = sym.get_plt_idx(ctx) * sizeof(ElfRel<E>);
|
||||
*(ul32 *)(buf + 7) = sym.get_gotplt_addr(ctx) - ctx.got->shdr.sh_addr;
|
||||
} else {
|
||||
static const u8 insn[] = {
|
||||
0xf3, 0x0f, 0x1e, 0xfb, // endbr32
|
||||
0xb9, 0, 0, 0, 0, // mov $reloc_offset, %ecx
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, // (padding)
|
||||
0xb9, 0, 0, 0, 0, // mov $reloc_offset, %ecx
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ul32 *)(buf + 5) = sym.get_plt_idx(ctx) * sizeof(ElfRel<E>);
|
||||
*(ul32 *)(buf + 11) = sym.get_gotplt_addr(ctx);
|
||||
*(ul32 *)(buf + 1) = sym.get_plt_idx(ctx) * sizeof(ElfRel<E>);
|
||||
*(ul32 *)(buf + 7) = sym.get_gotplt_addr(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,20 +156,18 @@ template <>
|
||||
void write_pltgot_entry(Context<E> &ctx, u8 *buf, Symbol<E> &sym) {
|
||||
if (ctx.arg.pic) {
|
||||
static const u8 insn[] = {
|
||||
0xf3, 0x0f, 0x1e, 0xfb, // endbr32
|
||||
0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
0xff, 0xa3, 0, 0, 0, 0, // jmp *foo@GOT(%ebx)
|
||||
0xcc, 0xcc, // (padding)
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ul32 *)(buf + 6) = sym.get_got_pltgot_addr(ctx) - ctx.got->shdr.sh_addr;
|
||||
*(ul32 *)(buf + 2) = sym.get_got_pltgot_addr(ctx) - ctx.got->shdr.sh_addr;
|
||||
} else {
|
||||
static const u8 insn[] = {
|
||||
0xf3, 0x0f, 0x1e, 0xfb, // endbr32
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // (padding)
|
||||
0xff, 0x25, 0, 0, 0, 0, // jmp *foo@GOT
|
||||
0xcc, 0xcc, // (padding)
|
||||
};
|
||||
memcpy(buf, insn, sizeof(insn));
|
||||
*(ul32 *)(buf + 6) = sym.get_got_pltgot_addr(ctx);
|
||||
*(ul32 *)(buf + 2) = sym.get_got_pltgot_addr(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,11 +237,10 @@ static void relax_ld_to_le(u8 *loc, ElfRel<E> rel, u64 tls_size) {
|
||||
case R_386_GOT32X: {
|
||||
static const u8 insn[] = {
|
||||
0x65, 0xa1, 0, 0, 0, 0, // mov %gs:0, %eax
|
||||
0x2d, 0, 0, 0, 0, // sub $tls_size, %eax
|
||||
0x90, // nop
|
||||
0x81, 0xe8, 0, 0, 0, 0, // sub $tls_size, %eax
|
||||
};
|
||||
memcpy(loc - 2, insn, sizeof(insn));
|
||||
*(ul32 *)(loc + 5) = tls_size;
|
||||
*(ul32 *)(loc + 6) = tls_size;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -294,19 +288,16 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = get_addend(*this, rel);
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_386_8:
|
||||
check(S + A, 0, 1 << 8);
|
||||
@@ -406,6 +397,10 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
// mov %reg, %eax
|
||||
// call *(%eax)
|
||||
// R_386_TLS_DESC_CALL foo
|
||||
//
|
||||
// Note that the compiler always uses the local-exec TLS model
|
||||
// for -fno-pic, so TLSDESC code is always PIC (i.e. uses %ebx to
|
||||
// store the address of GOT.)
|
||||
if (sym.has_tlsdesc(ctx)) {
|
||||
*(ul32 *)loc = sym.get_tlsdesc_addr(ctx) + A - GOT;
|
||||
} else if (sym.has_gottp(ctx)) {
|
||||
@@ -449,13 +444,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
@@ -464,6 +452,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
u64 A = frag ? frag_addend : get_addend(*this, rel);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, val, i, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_386_8:
|
||||
check(S + A, 0, 1 << 8);
|
||||
|
||||
+17
-25
@@ -51,7 +51,7 @@ static u64 hi20(u64 val, u64 pc) {
|
||||
return bits(page(val + 0x800) - page(pc), 31, 12);
|
||||
}
|
||||
|
||||
static u64 hi32(u64 val, u64 pc) {
|
||||
static u64 higher(u64 val, u64 pc) {
|
||||
// A PC-relative 64-bit address is materialized with the following
|
||||
// instructions for the large code model:
|
||||
//
|
||||
@@ -72,11 +72,11 @@ static u64 hi32(u64 val, u64 pc) {
|
||||
}
|
||||
|
||||
static u64 higher20(u64 val, u64 pc) {
|
||||
return bits(hi32(val, pc), 51, 32);
|
||||
return bits(higher(val, pc), 51, 32);
|
||||
}
|
||||
|
||||
static u64 highest12(u64 val, u64 pc) {
|
||||
return bits(hi32(val, pc), 63, 52);
|
||||
return bits(higher(val, pc), 63, 52);
|
||||
}
|
||||
|
||||
static void write_k12(u8 *loc, u32 val) {
|
||||
@@ -138,6 +138,7 @@ static bool is_relaxable_got_load(Context<E> &ctx, InputSection<E> &isec, i64 i)
|
||||
if (ctx.arg.relax &&
|
||||
sym.is_pcrel_linktime_const(ctx) &&
|
||||
i + 3 < rels.size() &&
|
||||
rels[i + 1].r_type == R_LARCH_RELAX &&
|
||||
rels[i + 2].r_type == R_LARCH_GOT_PC_LO12 &&
|
||||
rels[i + 2].r_offset == rels[i].r_offset + 4 &&
|
||||
rels[i + 3].r_type == R_LARCH_RELAX) {
|
||||
@@ -297,20 +298,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
i64 r_offset = rel.r_offset - r_delta;
|
||||
u8 *loc = base + r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
auto check_branch = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val & 0b11)
|
||||
Error(ctx) << *this << ": misaligned symbol " << sym
|
||||
<< " for relocation " << rel;
|
||||
check(val, lo, hi);
|
||||
};
|
||||
|
||||
// Unlike other psABIs, the LoongArch ABI uses the same relocation
|
||||
// types to refer to GOT entries for thread-local symbols and regular
|
||||
// ones. Therefore, G may refer to a TLSGD or a regular GOT slot
|
||||
@@ -334,10 +321,21 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
u64 G = got_idx * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
auto check_branch = [&](i64 val, i64 lo, i64 hi) {
|
||||
check(val, lo, hi);
|
||||
if (val & 0b11)
|
||||
Error(ctx) << *this << ": misaligned symbol " << sym
|
||||
<< " for relocation " << rel;
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_LARCH_32:
|
||||
if constexpr (E::is_64)
|
||||
*(ul32 *)loc = S + A;
|
||||
assert(E::is_64);
|
||||
*(ul32 *)loc = S + A;
|
||||
break;
|
||||
case R_LARCH_B16:
|
||||
check_branch(S + A - P, -(1 << 17), 1 << 17);
|
||||
@@ -590,10 +588,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
// pcaddi $a0, foo@GOTDESC
|
||||
// ld.d $ra, $a0, 0
|
||||
// jirl $ra, $ra, 0
|
||||
//
|
||||
// If the code-shrinking relaxation is disabled, we may leave
|
||||
// original useless instructions instead of deleting them, but we
|
||||
// accept that because relaxations are enabled by default.
|
||||
if (sym.has_tlsdesc(ctx) && removed_bytes == 0)
|
||||
write_j20(loc, hi20(sym.get_tlsdesc_addr(ctx) + A, P));
|
||||
break;
|
||||
@@ -601,8 +595,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
if (sym.has_tlsdesc(ctx) && removed_bytes == 0) {
|
||||
i64 dist = sym.get_tlsdesc_addr(ctx) + A - P;
|
||||
if (is_int(dist, 22)) {
|
||||
// If we can directly materialize the PC-relative address
|
||||
// with pcaddi, do that.
|
||||
*(ul32 *)loc = 0x1800'0000 | get_rd(*(ul32 *)loc); // pcaddi
|
||||
write_j20(loc, dist >> 2);
|
||||
} else {
|
||||
|
||||
+7
-10
@@ -86,11 +86,14 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
auto write16 = [&](u64 val) {
|
||||
@@ -113,12 +116,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
*loc = val;
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_68K_32:
|
||||
break;
|
||||
|
||||
+13
-22
@@ -162,13 +162,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
@@ -176,6 +169,10 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
u64 TOC = ctx.extra.TOC->value;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_PPC64_TOC:
|
||||
break;
|
||||
@@ -293,13 +290,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
@@ -307,6 +297,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, val, i, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_PPC64_ADDR64:
|
||||
if (std::optional<u64> val = get_tombstone(sym, frag))
|
||||
@@ -314,12 +308,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
else
|
||||
*(ub64 *)loc = S + A;
|
||||
break;
|
||||
case R_PPC64_ADDR32: {
|
||||
i64 val = S + A;
|
||||
check(val, 0, 1LL << 32);
|
||||
*(ub32 *)loc = val;
|
||||
case R_PPC64_ADDR32:
|
||||
check(S + A, 0, 1LL << 32);
|
||||
*(ub32 *)loc = S + A;
|
||||
break;
|
||||
}
|
||||
case R_PPC64_DTPREL64:
|
||||
*(ub64 *)loc = S + A - ctx.dtp_addr;
|
||||
break;
|
||||
@@ -509,7 +501,6 @@ get_relocation_at(Context<E> &ctx, InputSection<E> &isec, i64 offset) {
|
||||
|
||||
namespace {
|
||||
struct OpdSymbol {
|
||||
bool operator<(const OpdSymbol &x) const { return r_offset < x.r_offset; }
|
||||
u64 r_offset = 0;
|
||||
Symbol<E> *sym = nullptr;
|
||||
};
|
||||
@@ -517,7 +508,7 @@ struct OpdSymbol {
|
||||
|
||||
static Symbol<E> *
|
||||
get_opd_sym_at(std::span<OpdSymbol> syms, u64 offset) {
|
||||
auto it = std::lower_bound(syms.begin(), syms.end(), OpdSymbol{offset});
|
||||
auto it = ranges::lower_bound(syms, offset, {}, &OpdSymbol::r_offset);
|
||||
if (it == syms.end())
|
||||
return nullptr;
|
||||
if (it->r_offset != offset)
|
||||
@@ -599,7 +590,7 @@ void ppc64v1_rewrite_opd(Context<E> &ctx) {
|
||||
}
|
||||
|
||||
// Sort symbols so that get_opd_sym_at() can do binary search.
|
||||
sort(opd_syms);
|
||||
ranges::stable_sort(opd_syms, {}, &OpdSymbol::r_offset);
|
||||
|
||||
// Rewrite relocations so that they directly refer to .opd.
|
||||
for (std::unique_ptr<InputSection<E>> &isec : file->sections) {
|
||||
|
||||
+7
-12
@@ -354,13 +354,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
@@ -368,6 +361,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_PPC64_ADDR64:
|
||||
if (std::optional<u64> val = get_tombstone(sym, frag))
|
||||
@@ -375,12 +372,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
else
|
||||
*(ul64 *)loc = S + A;
|
||||
break;
|
||||
case R_PPC64_ADDR32: {
|
||||
i64 val = S + A;
|
||||
check(val, 0, 1LL << 32);
|
||||
*(ul32 *)loc = val;
|
||||
case R_PPC64_ADDR32:
|
||||
check(S + A, 0, 1LL << 32);
|
||||
*(ul32 *)loc = S + A;
|
||||
break;
|
||||
}
|
||||
case R_PPC64_DTPREL64:
|
||||
*(ul64 *)loc = S + A - ctx.dtp_addr;
|
||||
break;
|
||||
|
||||
+52
-57
@@ -243,6 +243,26 @@ find_paired_reloc(Context<E> &ctx, InputSection<E> &isec,
|
||||
Fatal(ctx) << isec << ": paired relocation is missing: " << i;
|
||||
}
|
||||
|
||||
// Returns true if isec's i'th relocation refers to the following
|
||||
// GOT-load instructioon pair, which is an expeanded form of
|
||||
// `la t0, foo` pseudo assembly instruction.
|
||||
//
|
||||
// .L0
|
||||
// auipc t0, 0 # R_RISCV_GOT_HI20(foo), R_RISCV_RELAX
|
||||
// ld t0, 0(t0) # R_RISCV_PCREL_LO12_I(.L0), R_RISCV_RELAX
|
||||
static bool is_got_load_pair(Context<E> &ctx, InputSection<E> &isec,
|
||||
std::span<const ElfRel<E>> rels, i64 i) {
|
||||
u8 *buf = (u8 *)isec.contents.data();
|
||||
return i + 3 < rels.size() &&
|
||||
rels[i].r_type == R_RISCV_GOT_HI20 &&
|
||||
rels[i + 1].r_type == R_RISCV_RELAX &&
|
||||
rels[i + 2].r_type == R_RISCV_PCREL_LO12_I &&
|
||||
rels[i + 3].r_type == R_RISCV_RELAX &&
|
||||
rels[i].r_offset == rels[i + 2].r_offset - 4 &&
|
||||
rels[i].r_offset == isec.file.symbols[rels[i + 2].r_sym]->value &&
|
||||
get_rd(buf + rels[i].r_offset) == get_rd(buf + rels[i + 2].r_offset);
|
||||
}
|
||||
|
||||
template <>
|
||||
void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
std::span<const ElfRel<E>> rels = get_rels(ctx);
|
||||
@@ -271,23 +291,20 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
i64 r_offset = rel.r_offset - r_delta;
|
||||
u8 *loc = base + r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_RISCV_32:
|
||||
if constexpr (E::is_64)
|
||||
*(U32<E> *)loc = S + A;
|
||||
assert(E::is_64);
|
||||
*(U32<E> *)loc = S + A;
|
||||
break;
|
||||
case R_RISCV_64:
|
||||
break;
|
||||
@@ -350,27 +367,20 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
i += 3;
|
||||
} else {
|
||||
assert(removed_bytes == 0);
|
||||
if (ctx.arg.relax &&
|
||||
sym.is_pcrel_linktime_const(ctx) &&
|
||||
i + 3 < rels.size() &&
|
||||
rels[i + 1].r_type == R_RISCV_RELAX &&
|
||||
rels[i + 2].r_type == R_RISCV_PCREL_LO12_I &&
|
||||
rels[i + 2].r_offset == rels[i].r_offset + 4 &&
|
||||
file.symbols[rels[i + 2].r_sym]->value == r_offset &&
|
||||
rels[i + 3].r_type == R_RISCV_RELAX) {
|
||||
i64 val = S + A - P;
|
||||
if (rd == get_rd(buf + rel.r_offset + 4) && (i32)val == val) {
|
||||
// auipc <rd>, %hi20(val)
|
||||
write_utype(loc, val);
|
||||
|
||||
// addi <rd>, <rd>, %lo12(val)
|
||||
*(ul32 *)(loc + 4) = 0b0010011 | (rd << 15) | (rd << 7);
|
||||
write_itype(loc + 4, val);
|
||||
i += 3;
|
||||
break;
|
||||
}
|
||||
i64 val = S + A - P;
|
||||
if (ctx.arg.relax && sym.is_pcrel_linktime_const(ctx) &&
|
||||
is_got_load_pair(ctx, *this, rels, i) && is_int(val, 32)) {
|
||||
// auipc <rd>, %hi20(val)
|
||||
write_utype(loc, val);
|
||||
|
||||
// addi <rd>, <rd>, %lo12(val)
|
||||
*(ul32 *)(loc + 4) = 0b0010011 | (rd << 15) | (rd << 7);
|
||||
write_itype(loc + 4, val);
|
||||
i += 3;
|
||||
} else {
|
||||
write_utype(loc, G + GOT + A - P);
|
||||
}
|
||||
write_utype(loc, G + GOT + A - P);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -905,34 +915,22 @@ void shrink_section(Context<E> &ctx, InputSection<E> &isec) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case R_RISCV_GOT_HI20: {
|
||||
case R_RISCV_GOT_HI20:
|
||||
// A GOT_HI20 followed by a PCREL_LO12_I is used to load a value from
|
||||
// GOT. If the loaded value is a link-time constant, we can rewrite
|
||||
// the instructions to directly materialize the value, eliminating a
|
||||
// memory load.
|
||||
if (sym.is_absolute() &&
|
||||
i + 3 < rels.size() &&
|
||||
rels[i + 1].r_type == R_RISCV_RELAX &&
|
||||
rels[i + 2].r_type == R_RISCV_PCREL_LO12_I &&
|
||||
rels[i + 2].r_offset == rels[i].r_offset + 4 &&
|
||||
isec.file.symbols[rels[i + 2].r_sym]->value == rels[i].r_offset &&
|
||||
rels[i + 3].r_type == R_RISCV_RELAX) {
|
||||
i64 rd = get_rd(buf + r.r_offset);
|
||||
|
||||
if (rd == get_rd(buf + r.r_offset + 4)) {
|
||||
u64 val = sym.get_addr(ctx) + r.r_addend;
|
||||
|
||||
if (use_rvc && rd != 0 && is_int(val, 6)) {
|
||||
// Replace AUIPC + LD with C.LI.
|
||||
remove(6);
|
||||
} else if (is_int(val, 12)) {
|
||||
// Replace AUIPC + LD with ADDI.
|
||||
remove(4);
|
||||
}
|
||||
if (sym.is_absolute() && is_got_load_pair(ctx, isec, rels, i)) {
|
||||
u64 val = sym.get_addr(ctx) + r.r_addend;
|
||||
if (use_rvc && is_int(val, 6) && get_rd(buf + r.r_offset) != 0) {
|
||||
// Replace AUIPC + LD with C.LI.
|
||||
remove(6);
|
||||
} else if (is_int(val, 12)) {
|
||||
// Replace AUIPC + LD with ADDI.
|
||||
remove(4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case R_RISCV_HI20: {
|
||||
u64 val = sym.get_addr(ctx) + r.r_addend;
|
||||
i64 rd = get_rd(buf + r.r_offset);
|
||||
@@ -1117,15 +1115,12 @@ static std::vector<Extn> merge_extensions(std::span<Extn> x, std::span<Extn> y)
|
||||
return vec;
|
||||
}
|
||||
|
||||
static std::string to_string(const Extn &e) {
|
||||
return e.name + std::to_string(e.major) + "p" + std::to_string(e.minor);
|
||||
}
|
||||
|
||||
static std::string to_string(std::span<Extn> v) {
|
||||
std::string str = to_string(v[0]);
|
||||
for (i64 i = 1; i < v.size(); i++)
|
||||
str += "_" + to_string(v[i]);
|
||||
return str;
|
||||
std::ostringstream os;
|
||||
os << v[0].name << v[0].major << 'p' << v[0].minor;
|
||||
for (Extn &e : v.subspan(1))
|
||||
os << '_' << e.name << e.major << 'p' << e.minor;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
+16
-23
@@ -124,28 +124,24 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
auto check_dbl = [&](i64 val, i64 lo, i64 hi) {
|
||||
check(val, lo, hi);
|
||||
|
||||
// R_390_*DBL relocs should never refer a symbol at an odd address
|
||||
if (val & 1)
|
||||
Error(ctx) << *this << ": misaligned symbol " << sym
|
||||
<< " for relocation " << rel;
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
auto check_dbl = [&](i64 val, i64 lo, i64 hi) {
|
||||
// R_390_*DBL relocs should never refer to a symbol at an odd address
|
||||
check(val, lo, hi);
|
||||
if (val & 1)
|
||||
Error(ctx) << *this << ": misaligned symbol " << sym
|
||||
<< " for relocation " << rel;
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_390_64:
|
||||
break;
|
||||
@@ -348,13 +344,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
@@ -362,6 +351,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, val, i, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_390_32:
|
||||
check(S + A, 0, 1LL << 32);
|
||||
|
||||
+8
-17
@@ -51,9 +51,6 @@
|
||||
// address. That also means each function needs to execute the above piece
|
||||
// of code to become position-independent.
|
||||
//
|
||||
// This scheme is very similar to i386. That may not be a coincidence
|
||||
// because the i386 ELF psABI is created by Sun Microsystems too.
|
||||
//
|
||||
// https://github.com/rui314/psabi/blob/main/sparc.pdf
|
||||
|
||||
#include "mold.h"
|
||||
@@ -150,19 +147,16 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_idx(ctx) * sizeof(Word<E>);
|
||||
u64 GOT = ctx.got->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_SPARC_5:
|
||||
check(S + A, 0, 1 << 5);
|
||||
@@ -466,13 +460,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
@@ -480,6 +467,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
check_range(ctx, val, i, lo, hi);
|
||||
};
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_SPARC_64:
|
||||
case R_SPARC_UA64:
|
||||
|
||||
+15
-21
@@ -442,11 +442,14 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_addr(ctx) - ctx.gotplt->shdr.sh_addr;
|
||||
u64 GOT = ctx.gotplt->shdr.sh_addr;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
auto write32 = [&](u64 val) {
|
||||
@@ -459,12 +462,6 @@ void InputSection<E>::apply_reloc_alloc(Context<E> &ctx, u8 *base) {
|
||||
*(ul32 *)loc = val;
|
||||
};
|
||||
|
||||
u64 S = sym.get_addr(ctx);
|
||||
u64 A = rel.r_addend;
|
||||
u64 P = get_addr() + rel.r_offset;
|
||||
u64 G = sym.get_got_addr(ctx) - ctx.gotplt->shdr.sh_addr;
|
||||
u64 GOT = ctx.gotplt->shdr.sh_addr;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_X86_64_8:
|
||||
check(S + A, 0, 1 << 8);
|
||||
@@ -669,11 +666,15 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
u8 *loc = base + rel.r_offset;
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
auto check = [&](i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val)
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
check_range(ctx, i, val, lo, hi);
|
||||
};
|
||||
|
||||
auto write32 = [&](u64 val) {
|
||||
@@ -686,13 +687,6 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
|
||||
*(ul32 *)loc = val;
|
||||
};
|
||||
|
||||
SectionFragment<E> *frag;
|
||||
i64 frag_addend;
|
||||
std::tie(frag, frag_addend) = get_fragment(ctx, rel);
|
||||
|
||||
u64 S = frag ? frag->get_addr(ctx) : sym.get_addr(ctx);
|
||||
u64 A = frag ? frag_addend : (i64)rel.r_addend;
|
||||
|
||||
switch (rel.r_type) {
|
||||
case R_X86_64_8:
|
||||
check(S + A, 0, 1 << 8);
|
||||
|
||||
+19
-1
@@ -41,6 +41,8 @@ Options:
|
||||
-N, --omagic Do not page align data; do not make text readonly
|
||||
--no-omagic
|
||||
-O NUMBER Ignored
|
||||
-P AUDITLIB, --depaudit AUDITLIB
|
||||
Set DT_DEPAUDIT to the specified value
|
||||
-S, --strip-debug Strip .debug_* sections
|
||||
-T FILE, --script FILE Read linker script
|
||||
-X, --discard-locals Discard temporary local symbols
|
||||
@@ -76,6 +78,7 @@ Options:
|
||||
--no-apply-dynamic-relocs
|
||||
--as-needed Only set DT_NEEDED if used
|
||||
--no-as-needed
|
||||
--audit LIBNAME Set DT_AUDIT to the specified value
|
||||
--build-id [none,md5,sha1,sha256,fast,uuid,HEXSTRING]
|
||||
Generate build ID
|
||||
--no-build-id
|
||||
@@ -715,8 +718,11 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
||||
<< " elf64briscv\n elf32lriscv\n elf32briscv\n"
|
||||
<< " elf32ppc\n elf64ppc\n elf64lppc\n elf64_s390\n"
|
||||
<< " elf64_sparc\n m68kelf\n shlelf_linux\n"
|
||||
<< " shelf_linux\n elf64loongarch\n elf32loongarch";
|
||||
<< " shelf_linux\n elf64loongarch\n elf32loongarch\n"
|
||||
<< " arclinux";
|
||||
version_shown = true;
|
||||
} else if (read_arg("mllvm")) {
|
||||
ctx.arg.plugin_opt.emplace_back(arg);
|
||||
} else if (read_arg("m")) {
|
||||
if (arg == "elf_x86_64") {
|
||||
ctx.arg.emulation = X86_64::name;
|
||||
@@ -756,6 +762,8 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
||||
ctx.arg.emulation = LOONGARCH64::name;
|
||||
} else if (arg == "elf32loongarch") {
|
||||
ctx.arg.emulation = LOONGARCH32::name;
|
||||
} else if (arg == "arclinux") {
|
||||
ctx.arg.emulation = ARC::name;
|
||||
} else {
|
||||
Fatal(ctx) << "unknown -m argument: " << arg;
|
||||
}
|
||||
@@ -890,6 +898,14 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
||||
}
|
||||
} else if (read_arg("soname") || read_arg("h")) {
|
||||
ctx.arg.soname = arg;
|
||||
} else if (read_arg("audit")) {
|
||||
if (!ctx.arg.audit.empty())
|
||||
ctx.arg.audit += ':';
|
||||
ctx.arg.audit += std::string(arg);
|
||||
} else if (read_arg("depaudit") || read_arg("P")) {
|
||||
if (!ctx.arg.depaudit.empty())
|
||||
ctx.arg.depaudit += ':';
|
||||
ctx.arg.depaudit += std::string(arg);
|
||||
} else if (read_flag("allow-multiple-definition")) {
|
||||
ctx.arg.allow_multiple_definition = true;
|
||||
} else if (read_flag("apply-dynamic-relocs")) {
|
||||
@@ -1333,6 +1349,8 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
|
||||
} else if (read_z_arg("common-page-size")) {
|
||||
} else if (read_flag("no-keep-memory")) {
|
||||
} else if (read_arg("max-cache-size")) {
|
||||
} else if (read_flag("mmap-output-file")) {
|
||||
} else if (read_flag("no-mmap-output-file")) {
|
||||
} else if (read_arg("version-script")) {
|
||||
version_scripts.push_back(arg);
|
||||
} else if (read_arg("dynamic-list")) {
|
||||
|
||||
+69
@@ -1038,4 +1038,73 @@ std::string rel_to_string<LOONGARCH32>(u32 r_type) {
|
||||
return rel_to_string<LOONGARCH64>(r_type);
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string rel_to_string<ARC>(u32 r_type) {
|
||||
switch (r_type) {
|
||||
CASE(R_ARC_8);
|
||||
CASE(R_ARC_16);
|
||||
CASE(R_ARC_24);
|
||||
CASE(R_ARC_32);
|
||||
CASE(R_ARC_N8);
|
||||
CASE(R_ARC_N16);
|
||||
CASE(R_ARC_N24);
|
||||
CASE(R_ARC_N32);
|
||||
CASE(R_ARC_SDA);
|
||||
CASE(R_ARC_SECTOFF);
|
||||
CASE(R_ARC_S21H_PCREL);
|
||||
CASE(R_ARC_S21W_PCREL);
|
||||
CASE(R_ARC_S25H_PCREL);
|
||||
CASE(R_ARC_S25W_PCREL);
|
||||
CASE(R_ARC_SDA32);
|
||||
CASE(R_ARC_SDA_LDST);
|
||||
CASE(R_ARC_SDA_LDST1);
|
||||
CASE(R_ARC_SDA_LDST2);
|
||||
CASE(R_ARC_SDA16_LD);
|
||||
CASE(R_ARC_SDA16_LD1);
|
||||
CASE(R_ARC_SDA16_LD2);
|
||||
CASE(R_ARC_S13_PCREL);
|
||||
CASE(R_ARC_W);
|
||||
CASE(R_ARC_32_ME);
|
||||
CASE(R_ARC_32_ME_S);
|
||||
CASE(R_ARC_N32_ME);
|
||||
CASE(R_ARC_SECTOFF_ME);
|
||||
CASE(R_ARC_SDA32_ME);
|
||||
CASE(R_ARC_W_ME);
|
||||
CASE(R_ARC_SECTOFF_ME_1);
|
||||
CASE(R_ARC_SECTOFF_ME_2);
|
||||
CASE(R_ARC_SECTOFF_1);
|
||||
CASE(R_ARC_SECTOFF_2);
|
||||
CASE(R_ARC_SDA_12);
|
||||
CASE(R_ARC_SDA16_ST2);
|
||||
CASE(R_ARC_32_PCREL);
|
||||
CASE(R_ARC_PC32);
|
||||
CASE(R_ARC_GOT32);
|
||||
CASE(R_ARC_GOTPC32);
|
||||
CASE(R_ARC_PLT32);
|
||||
CASE(R_ARC_COPY);
|
||||
CASE(R_ARC_GLOB_DAT);
|
||||
CASE(R_ARC_JMP_SLOT);
|
||||
CASE(R_ARC_RELATIVE);
|
||||
CASE(R_ARC_GOTOFF);
|
||||
CASE(R_ARC_GOTPC);
|
||||
CASE(R_ARC_S21W_PCREL_PLT);
|
||||
CASE(R_ARC_S25H_PCREL_PLT);
|
||||
CASE(R_ARC_JLI_SECTOFF);
|
||||
CASE(R_ARC_TLS_DTPMOD);
|
||||
CASE(R_ARC_TLS_TPOFF);
|
||||
CASE(R_ARC_TLS_GD_GOT);
|
||||
CASE(R_ARC_TLS_GD_LD);
|
||||
CASE(R_ARC_TLS_GD_CALL);
|
||||
CASE(R_ARC_TLS_IE_GOT);
|
||||
CASE(R_ARC_TLS_DTPOFF);
|
||||
CASE(R_ARC_TLS_DTPOFF_S9);
|
||||
CASE(R_ARC_TLS_LE_S9);
|
||||
CASE(R_ARC_TLS_LE_32);
|
||||
CASE(R_ARC_S25W_PCREL_PLT);
|
||||
CASE(R_ARC_S21H_PCREL_PLT);
|
||||
CASE(R_ARC_NPS_CMEM16);
|
||||
}
|
||||
return unknown_type(r_type);
|
||||
}
|
||||
|
||||
} // namespace mold
|
||||
@@ -28,6 +28,7 @@ struct SH4LE;
|
||||
struct SH4BE;
|
||||
struct LOONGARCH64;
|
||||
struct LOONGARCH32;
|
||||
struct ARC;
|
||||
|
||||
template <typename E> struct ElfSym;
|
||||
template <typename E> struct ElfShdr;
|
||||
@@ -78,6 +79,7 @@ enum : u32 {
|
||||
SHT_GROUP = 17,
|
||||
SHT_SYMTAB_SHNDX = 18,
|
||||
SHT_RELR = 19,
|
||||
SHT_CREL = 0x40000014,
|
||||
SHT_LOOS = 0x60000000,
|
||||
SHT_LLVM_ADDRSIG = 0x6fff4c03,
|
||||
SHT_GNU_HASH = 0x6ffffff6,
|
||||
@@ -87,6 +89,7 @@ enum : u32 {
|
||||
SHT_HIOS = 0x6fffffff,
|
||||
SHT_X86_64_UNWIND = 0x70000001,
|
||||
SHT_ARM_EXIDX = 0x70000001,
|
||||
SHT_ARC_ATTRIBUTES = 0x70000001,
|
||||
SHT_ARM_ATTRIBUTES = 0x70000003,
|
||||
SHT_RISCV_ATTRIBUTES = 0x70000003,
|
||||
SHT_LOUSER = 0x80000000,
|
||||
@@ -234,6 +237,7 @@ enum : u32 {
|
||||
EM_SPARC64 = 43,
|
||||
EM_X86_64 = 62,
|
||||
EM_AARCH64 = 183,
|
||||
EM_ARC_COMPACT2 = 195,
|
||||
EM_RISCV = 243,
|
||||
EM_LOONGARCH = 258,
|
||||
};
|
||||
@@ -284,6 +288,8 @@ enum : u32 {
|
||||
DT_RELR = 36,
|
||||
DT_RELRENT = 37,
|
||||
DT_GNU_HASH = 0x6ffffef5,
|
||||
DT_DEPAUDIT = 0x6ffffefb,
|
||||
DT_AUDIT = 0x6ffffefc,
|
||||
DT_VERSYM = 0x6ffffff0,
|
||||
DT_RELACOUNT = 0x6ffffff9,
|
||||
DT_RELCOUNT = 0x6ffffffa,
|
||||
@@ -1359,6 +1365,71 @@ enum : u32 {
|
||||
R_LARCH_TLS_DESC_PCREL20_S2 = 126,
|
||||
};
|
||||
|
||||
enum : u32 {
|
||||
R_ARC_8 = 1,
|
||||
R_ARC_16 = 2,
|
||||
R_ARC_24 = 3,
|
||||
R_ARC_32 = 4,
|
||||
R_ARC_N8 = 8,
|
||||
R_ARC_N16 = 9,
|
||||
R_ARC_N24 = 10,
|
||||
R_ARC_N32 = 11,
|
||||
R_ARC_SDA = 12,
|
||||
R_ARC_SECTOFF = 13,
|
||||
R_ARC_S21H_PCREL = 14,
|
||||
R_ARC_S21W_PCREL = 15,
|
||||
R_ARC_S25H_PCREL = 16,
|
||||
R_ARC_S25W_PCREL = 17,
|
||||
R_ARC_SDA32 = 18,
|
||||
R_ARC_SDA_LDST = 19,
|
||||
R_ARC_SDA_LDST1 = 20,
|
||||
R_ARC_SDA_LDST2 = 21,
|
||||
R_ARC_SDA16_LD = 22,
|
||||
R_ARC_SDA16_LD1 = 23,
|
||||
R_ARC_SDA16_LD2 = 24,
|
||||
R_ARC_S13_PCREL = 25,
|
||||
R_ARC_W = 26,
|
||||
R_ARC_32_ME = 27,
|
||||
R_ARC_32_ME_S = 105,
|
||||
R_ARC_N32_ME = 28,
|
||||
R_ARC_SECTOFF_ME = 29,
|
||||
R_ARC_SDA32_ME = 30,
|
||||
R_ARC_W_ME = 31,
|
||||
R_ARC_SECTOFF_ME_1 = 41,
|
||||
R_ARC_SECTOFF_ME_2 = 42,
|
||||
R_ARC_SECTOFF_1 = 43,
|
||||
R_ARC_SECTOFF_2 = 44,
|
||||
R_ARC_SDA_12 = 45,
|
||||
R_ARC_SDA16_ST2 = 48,
|
||||
R_ARC_32_PCREL = 49,
|
||||
R_ARC_PC32 = 50,
|
||||
R_ARC_GOT32 = 59,
|
||||
R_ARC_GOTPC32 = 51,
|
||||
R_ARC_PLT32 = 52,
|
||||
R_ARC_COPY = 53,
|
||||
R_ARC_GLOB_DAT = 54,
|
||||
R_ARC_JMP_SLOT = 55,
|
||||
R_ARC_RELATIVE = 56,
|
||||
R_ARC_GOTOFF = 57,
|
||||
R_ARC_GOTPC = 58,
|
||||
R_ARC_S21W_PCREL_PLT = 60,
|
||||
R_ARC_S25H_PCREL_PLT = 61,
|
||||
R_ARC_JLI_SECTOFF = 63,
|
||||
R_ARC_TLS_DTPMOD = 66,
|
||||
R_ARC_TLS_TPOFF = 68,
|
||||
R_ARC_TLS_GD_GOT = 69,
|
||||
R_ARC_TLS_GD_LD = 70,
|
||||
R_ARC_TLS_GD_CALL = 71,
|
||||
R_ARC_TLS_IE_GOT = 72,
|
||||
R_ARC_TLS_DTPOFF = 67,
|
||||
R_ARC_TLS_DTPOFF_S9 = 73,
|
||||
R_ARC_TLS_LE_S9 = 74,
|
||||
R_ARC_TLS_LE_32 = 75,
|
||||
R_ARC_S25W_PCREL_PLT = 76,
|
||||
R_ARC_S21H_PCREL_PLT = 77,
|
||||
R_ARC_NPS_CMEM16 = 78,
|
||||
};
|
||||
|
||||
// Returns true if a given relocation is of type used for direct
|
||||
// function call.
|
||||
template <typename E>
|
||||
@@ -1822,6 +1893,7 @@ template <typename E> concept is_sh4le = std::same_as<E, SH4LE>;
|
||||
template <typename E> concept is_sh4be = std::same_as<E, SH4BE>;
|
||||
template <typename E> concept is_loongarch64 = std::same_as<E, LOONGARCH64>;
|
||||
template <typename E> concept is_loongarch32 = std::same_as<E, LOONGARCH32>;
|
||||
template <typename E> concept is_arc = std::same_as<E, ARC>;
|
||||
|
||||
template <typename E> concept is_x86 = is_x86_64<E> || is_i386<E>;
|
||||
template <typename E> concept is_arm64 = is_arm64le<E> || is_arm64be<E>;
|
||||
@@ -1869,7 +1941,7 @@ struct I386 {
|
||||
static constexpr u32 e_machine = EM_386;
|
||||
static constexpr u32 plt_hdr_size = 16;
|
||||
static constexpr u32 plt_size = 16;
|
||||
static constexpr u32 pltgot_size = 16;
|
||||
static constexpr u32 pltgot_size = 8;
|
||||
static constexpr u8 filler[] = { 0xcc }; // int3
|
||||
|
||||
static constexpr u32 R_COPY = R_386_COPY;
|
||||
@@ -2225,4 +2297,27 @@ struct LOONGARCH32 {
|
||||
static constexpr u32 R_FUNCALL[] = { R_LARCH_B26, R_LARCH_CALL36 };
|
||||
};
|
||||
|
||||
struct ARC {
|
||||
static constexpr std::string_view name = "arc";
|
||||
static constexpr bool is_64 = false;
|
||||
static constexpr bool is_le = true;
|
||||
static constexpr bool is_rela = true;
|
||||
static constexpr u32 page_size = 8192;
|
||||
static constexpr u32 e_machine = EM_ARC_COMPACT2;
|
||||
static constexpr u32 plt_hdr_size = 24;
|
||||
static constexpr u32 plt_size = 16;
|
||||
static constexpr u32 pltgot_size = 16;
|
||||
static constexpr u8 filler[] = { 0, 0, 0, 0 };
|
||||
|
||||
static constexpr u32 R_COPY = R_ARC_COPY;
|
||||
static constexpr u32 R_GLOB_DAT = R_ARC_GLOB_DAT;
|
||||
static constexpr u32 R_JUMP_SLOT = R_ARC_JMP_SLOT;
|
||||
static constexpr u32 R_ABS = R_ARC_32;
|
||||
static constexpr u32 R_RELATIVE = R_ARC_RELATIVE;
|
||||
static constexpr u32 R_DTPOFF = R_ARC_TLS_DTPOFF;
|
||||
static constexpr u32 R_TPOFF = R_ARC_TLS_TPOFF;
|
||||
static constexpr u32 R_DTPMOD = R_ARC_TLS_DTPMOD;
|
||||
static constexpr u32 R_FUNCALL[] = { R_ARC_S25W_PCREL_PLT };
|
||||
};
|
||||
|
||||
} // namespace mold
|
||||
@@ -160,6 +160,8 @@ static std::string_view get_elf_type(u8 *buf) {
|
||||
return is_le ? SH4LE::name : SH4BE::name;
|
||||
case EM_LOONGARCH:
|
||||
return is_64 ? LOONGARCH64::name : LOONGARCH32::name;
|
||||
case EM_ARC_COMPACT2:
|
||||
return ARC::name;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
+1
-1
@@ -620,7 +620,7 @@ static std::vector<Compunit> read_compunits(Context<E> &ctx) {
|
||||
// Uniquify elements because GCC 11 seems to emit one record for each
|
||||
// comdat group which results in having a lot of duplicate records.
|
||||
tbb::parallel_for_each(cus, [](Compunit &cu) {
|
||||
sort(cu.nametypes);
|
||||
ranges::stable_sort(cu.nametypes);
|
||||
remove_duplicates(cu.nametypes);
|
||||
});
|
||||
|
||||
|
||||
+108
-64
@@ -93,12 +93,6 @@ InputFile<E>::InputFile(Context<E> &ctx, MappedFile *mf)
|
||||
shstrtab = this->get_string(ctx, shstrtab_idx);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
std::span<ElfPhdr<E>> InputFile<E>::get_phdrs() {
|
||||
ElfEhdr<E> &ehdr = *(ElfEhdr<E> *)mf->data;
|
||||
return {(ElfPhdr<E> *)(mf->data + ehdr.e_phoff), ehdr.e_phnum};
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
ElfShdr<E> *InputFile<E>::find_section(i64 type) {
|
||||
for (ElfShdr<E> &sec : elf_sections)
|
||||
@@ -236,6 +230,65 @@ static bool is_known_section_type(const ElfShdr<E> &shdr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SHT_CREL is an experimental alternative relocation table format
|
||||
// designed to reduce the size of the table. Only LLVM supports it
|
||||
// at the moment.
|
||||
//
|
||||
// This function converts a CREL relocation table to a regular one.
|
||||
template <typename E>
|
||||
std::vector<ElfRel<E>> decode_crel(Context<E> &ctx, ObjectFile<E> &file,
|
||||
const ElfShdr<E> &shdr) {
|
||||
u8 *p = (u8 *)file.get_string(ctx, shdr).data();
|
||||
u64 hdr = read_uleb(&p);
|
||||
i64 nrels = hdr >> 3;
|
||||
bool is_rela = hdr & 0b100;
|
||||
i64 scale = hdr & 0b11;
|
||||
|
||||
if (is_rela && !E::is_rela)
|
||||
Fatal(ctx) << file << ": CREL with addends is not supported for " << E::name;
|
||||
|
||||
u64 offset = 0;
|
||||
i64 type = 0;
|
||||
i64 symidx = 0;
|
||||
i64 addend = 0;
|
||||
|
||||
std::vector<ElfRel<E>> vec;
|
||||
vec.reserve(nrels);
|
||||
|
||||
while (vec.size() < nrels) {
|
||||
u8 flags = *p++;
|
||||
i64 nflags = is_rela ? 3 : 2;
|
||||
|
||||
// The first ULEB-128 encoded value is a concatenation of bit flags and
|
||||
// an offset delta. The delta may be very large to decrease the
|
||||
// current offset value by wrapping around. Combined, the encoded value
|
||||
// can be up to 67 bit long. Thus we can't simply use read_uleb() which
|
||||
// returns a u64.
|
||||
u64 delta;
|
||||
if (flags & 0x80)
|
||||
delta = (read_uleb(&p) << (7 - nflags)) | ((flags & 0x7f) >> nflags);
|
||||
else
|
||||
delta = flags >> nflags;
|
||||
offset += delta << scale;
|
||||
|
||||
if (flags & 1)
|
||||
symidx += read_sleb(&p);
|
||||
if (flags & 2)
|
||||
type += read_sleb(&p);
|
||||
if (is_rela && (flags & 4))
|
||||
addend += read_sleb(&p);
|
||||
vec.emplace_back(offset, type, symidx, addend);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
ComdatGroup *insert_comdat_group(Context<E> &ctx, std::string_view name) {
|
||||
typename decltype(ctx.comdat_groups)::const_accessor acc;
|
||||
ctx.comdat_groups.insert(acc, {name, ComdatGroup()});
|
||||
return const_cast<ComdatGroup *>(&acc->second);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void ObjectFile<E>::initialize_sections(Context<E> &ctx) {
|
||||
// Read sections
|
||||
@@ -264,6 +317,10 @@ void ObjectFile<E>::initialize_sections(Context<E> &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (is_arc<E>)
|
||||
if (shdr.sh_type == SHT_ARC_ATTRIBUTES)
|
||||
continue;
|
||||
|
||||
switch (shdr.sh_type) {
|
||||
case SHT_GROUP: {
|
||||
// Get the signature of this section group.
|
||||
@@ -294,12 +351,14 @@ void ObjectFile<E>::initialize_sections(Context<E> &ctx) {
|
||||
if (entries[0] != GRP_COMDAT)
|
||||
Fatal(ctx) << *this << ": unsupported SHT_GROUP format";
|
||||
|
||||
typename decltype(ctx.comdat_groups)::const_accessor acc;
|
||||
ctx.comdat_groups.insert(acc, {signature, ComdatGroup()});
|
||||
ComdatGroup *group = const_cast<ComdatGroup *>(&acc->second);
|
||||
ComdatGroup *group = insert_comdat_group(ctx, signature);
|
||||
comdat_groups.push_back({group, (i32)i, entries.subspan(1)});
|
||||
break;
|
||||
}
|
||||
case SHT_CREL:
|
||||
decoded_crel.resize(i + 1);
|
||||
decoded_crel[i] = decode_crel(ctx, *this, shdr);
|
||||
break;
|
||||
case SHT_REL:
|
||||
case SHT_RELA:
|
||||
case SHT_SYMTAB:
|
||||
@@ -354,7 +413,8 @@ void ObjectFile<E>::initialize_sections(Context<E> &ctx) {
|
||||
continue;
|
||||
|
||||
// Ignore section is specified by --discard-section.
|
||||
if (ctx.arg.discard_section.contains(name))
|
||||
if (!ctx.arg.discard_section.empty() &&
|
||||
ctx.arg.discard_section.contains(name))
|
||||
continue;
|
||||
|
||||
if (name == ".comment" &&
|
||||
@@ -436,16 +496,12 @@ void ObjectFile<E>::initialize_sections(Context<E> &ctx) {
|
||||
// Attach relocation sections to their target sections.
|
||||
for (i64 i = 0; i < this->elf_sections.size(); i++) {
|
||||
const ElfShdr<E> &shdr = this->elf_sections[i];
|
||||
if (shdr.sh_type != (E::is_rela ? SHT_RELA : SHT_REL))
|
||||
continue;
|
||||
|
||||
if (shdr.sh_info >= sections.size())
|
||||
Fatal(ctx) << *this << ": invalid relocated section index: "
|
||||
<< (u32)shdr.sh_info;
|
||||
|
||||
if (std::unique_ptr<InputSection<E>> &target = sections[shdr.sh_info]) {
|
||||
assert(target->relsec_idx == -1);
|
||||
target->relsec_idx = i;
|
||||
if (shdr.sh_type == (E::is_rela ? SHT_RELA : SHT_REL) ||
|
||||
shdr.sh_type == SHT_CREL) {
|
||||
if (std::unique_ptr<InputSection<E>> &target = sections[shdr.sh_info]) {
|
||||
assert(target->relsec_idx == -1);
|
||||
target->relsec_idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,6 +599,8 @@ void ObjectFile<E>::parse_ehframe(Context<E> &ctx) {
|
||||
i64 cie_offset = *(I32<E> *)(contents.data() + fdes[i].input_offset + 4);
|
||||
fdes[i].cie_idx = find_cie(fdes[i].input_offset + 4 - cie_offset);
|
||||
}
|
||||
|
||||
isec->is_alive = false;
|
||||
}
|
||||
|
||||
auto get_isec = [&](const FdeRecord<E> &fde) {
|
||||
@@ -551,8 +609,8 @@ void ObjectFile<E>::parse_ehframe(Context<E> &ctx) {
|
||||
|
||||
// We assume that FDEs for the same input sections are contiguous
|
||||
// in `fdes` vector.
|
||||
sort(fdes, [&](const FdeRecord<E> &a, const FdeRecord<E> &b) {
|
||||
return get_isec(a)->get_priority() < get_isec(b)->get_priority();
|
||||
ranges::stable_sort(fdes, {}, [&](const FdeRecord<E> &x) {
|
||||
return get_isec(x)->get_priority();
|
||||
});
|
||||
|
||||
// Associate FDEs to input sections.
|
||||
@@ -660,18 +718,14 @@ void ObjectFile<E>::initialize_symbols(Context<E> &ctx) {
|
||||
template <typename E>
|
||||
void ObjectFile<E>::sort_relocations(Context<E> &ctx) {
|
||||
if constexpr (is_riscv<E> || is_loongarch<E>) {
|
||||
auto less = [](const ElfRel<E> &a, const ElfRel<E> &b) {
|
||||
return a.r_offset < b.r_offset;
|
||||
};
|
||||
|
||||
for (i64 i = 1; i < sections.size(); i++) {
|
||||
std::unique_ptr<InputSection<E>> &isec = sections[i];
|
||||
if (!isec || !isec->is_alive || !(isec->shdr().sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
|
||||
std::span<ElfRel<E>> rels = isec->get_rels(ctx);
|
||||
if (!std::is_sorted(rels.begin(), rels.end(), less))
|
||||
sort(rels, less);
|
||||
if (!ranges::is_sorted(rels, {}, &ElfRel<E>::r_offset))
|
||||
ranges::stable_sort(rels, {}, &ElfRel<E>::r_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -848,16 +902,6 @@ void ObjectFile<E>::parse(Context<E> &ctx) {
|
||||
initialize_sections(ctx);
|
||||
initialize_symbols(ctx);
|
||||
sort_relocations(ctx);
|
||||
|
||||
// R_ARM_TARGET1 is typically used for entries in .init_array and may
|
||||
// be interpreted as REL32 or ABS32 depending on the target.
|
||||
// All targets we support handle it as if it were a ABS32.
|
||||
if constexpr (is_arm32<E>)
|
||||
for (std::unique_ptr<InputSection<E>> &isec : sections)
|
||||
if (isec && isec->is_alive)
|
||||
for (ElfRel<E> &r : isec->get_rels(ctx))
|
||||
if (r.r_type == R_ARM_TARGET1)
|
||||
r.r_type = R_ARM_ABS32;
|
||||
}
|
||||
|
||||
// Symbols with higher priorities overwrites symbols with lower priorities.
|
||||
@@ -872,6 +916,10 @@ void ObjectFile<E>::parse(Context<E> &ctx) {
|
||||
// 7. Unclaimed (nonexistent) symbol
|
||||
//
|
||||
// Ties are broken by file priority.
|
||||
//
|
||||
// Note that the above priorities are based on heuristics and not on exact
|
||||
// science. We tried several different orders and settled on the current
|
||||
// one just because it avoids link errors in all programs we've tested.
|
||||
template <typename E>
|
||||
static u64 get_rank(InputFile<E> *file, const ElfSym<E> &esym, bool is_in_archive) {
|
||||
auto get_sym_rank = [&] {
|
||||
@@ -1199,7 +1247,7 @@ std::string SharedFile<E>::get_soname(Context<E> &ctx) {
|
||||
if (ElfShdr<E> *sec = this->find_section(SHT_DYNAMIC))
|
||||
for (ElfDyn<E> &dyn : this->template get_data<ElfDyn<E>>(ctx, *sec))
|
||||
if (dyn.d_tag == DT_SONAME)
|
||||
return this->symbol_strtab.data() + dyn.d_val;
|
||||
return this->get_string(ctx, sec->sh_link).data() + dyn.d_val;
|
||||
|
||||
if (this->mf->given_fullpath)
|
||||
return this->filename;
|
||||
@@ -1258,30 +1306,23 @@ void SharedFile<E>::parse(Context<E> &ctx) {
|
||||
|
||||
template <typename E>
|
||||
std::vector<std::string_view> SharedFile<E>::get_dt_needed(Context<E> &ctx) {
|
||||
// Get the contents of the dynamic segment
|
||||
std::span<ElfDyn<E>> dynamic;
|
||||
for (ElfPhdr<E> &phdr : this->get_phdrs())
|
||||
if (phdr.p_type == PT_DYNAMIC)
|
||||
dynamic = {(ElfDyn<E> *)(this->mf->data + phdr.p_offset),
|
||||
(size_t)phdr.p_memsz / sizeof(ElfDyn<E>)};
|
||||
|
||||
// Find a string table
|
||||
char *strtab = nullptr;
|
||||
for (ElfDyn<E> &dyn : dynamic)
|
||||
if (dyn.d_tag == DT_STRTAB)
|
||||
strtab = (char *)this->mf->data + dyn.d_val;
|
||||
|
||||
if (!strtab)
|
||||
return {};
|
||||
|
||||
// Find all DT_NEEDED entries
|
||||
std::vector<std::string_view> vec;
|
||||
for (ElfDyn<E> &dyn : dynamic)
|
||||
if (dyn.d_tag == DT_NEEDED)
|
||||
vec.push_back(strtab + dyn.d_val);
|
||||
if (ElfShdr<E> *sec = this->find_section(SHT_DYNAMIC))
|
||||
for (ElfDyn<E> &dyn : this->template get_data<ElfDyn<E>>(ctx, *sec))
|
||||
if (dyn.d_tag == DT_NEEDED)
|
||||
vec.push_back(this->get_string(ctx, sec->sh_link).data() + dyn.d_val);
|
||||
return vec;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
std::string_view SharedFile<E>::get_dt_audit(Context<E> &ctx) {
|
||||
if (ElfShdr<E> *sec = this->find_section(SHT_DYNAMIC))
|
||||
for (ElfDyn<E> &dyn : this->template get_data<ElfDyn<E>>(ctx, *sec))
|
||||
if (dyn.d_tag == DT_AUDIT)
|
||||
return this->get_string(ctx, sec->sh_link).data() + dyn.d_val;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Symbol versioning is a GNU extension to the ELF file format. I don't
|
||||
// particularly like the feature as it complicates the semantics of
|
||||
// dynamic linking, but we need to support it anyway because it is
|
||||
@@ -1405,11 +1446,10 @@ std::span<Symbol<E> *> SharedFile<E>::get_symbols_at(Symbol<E> *sym) {
|
||||
});
|
||||
});
|
||||
|
||||
auto [begin, end] = std::equal_range(sorted_syms.begin(), sorted_syms.end(),
|
||||
sym, [](Symbol<E> *a, Symbol<E> *b) {
|
||||
return a->esym().st_value < b->esym().st_value;
|
||||
auto [begin, end] = ranges::equal_range(sorted_syms, sym->esym().st_value, {},
|
||||
[](Symbol<E> *x) {
|
||||
return x->esym().st_value;
|
||||
});
|
||||
|
||||
return {&*begin, (size_t)(end - begin)};
|
||||
}
|
||||
|
||||
@@ -1431,9 +1471,12 @@ i64 SharedFile<E>::get_alignment(Symbol<E> *sym) {
|
||||
|
||||
template <typename E>
|
||||
bool SharedFile<E>::is_readonly(Symbol<E> *sym) {
|
||||
ElfEhdr<E> &ehdr = *(ElfEhdr<E> *)this->mf->data;
|
||||
std::span<ElfPhdr<E>> phdrs((ElfPhdr<E> *)(this->mf->data + ehdr.e_phoff),
|
||||
ehdr.e_phnum);
|
||||
u64 val = sym->esym().st_value;
|
||||
|
||||
for (ElfPhdr<E> &phdr : this->get_phdrs())
|
||||
for (ElfPhdr<E> &phdr : phdrs)
|
||||
if ((phdr.p_type == PT_LOAD || phdr.p_type == PT_GNU_RELRO) &&
|
||||
!(phdr.p_flags & PF_W) &&
|
||||
phdr.p_vaddr <= val && val < phdr.p_vaddr + phdr.p_memsz)
|
||||
@@ -1489,6 +1532,7 @@ template class SharedFile<E>;
|
||||
template Symbol<E> *get_symbol(Context<E> &, std::string_view, std::string_view);
|
||||
template Symbol<E> *get_symbol(Context<E> &, std::string_view);
|
||||
template std::string_view demangle(const Symbol<E> &);
|
||||
template ComdatGroup *insert_comdat_group(Context<E> &, std::string_view);
|
||||
template std::ostream &operator<<(std::ostream &, const Symbol<E> &);
|
||||
template std::ostream &operator<<(std::ostream &, const InputFile<E> &);
|
||||
|
||||
|
||||
@@ -654,6 +654,7 @@ ObjectFile<E> *read_lto_object(Context<E> &ctx, MappedFile *mf) {
|
||||
|
||||
// Initialize esyms
|
||||
obj->lto_elf_syms.resize(plugin_symbols.size() + 1);
|
||||
obj->lto_comdat_groups.resize(plugin_symbols.size() + 1);
|
||||
i64 strtab_offset = 1;
|
||||
|
||||
for (i64 i = 0; i < plugin_symbols.size(); i++) {
|
||||
@@ -664,6 +665,13 @@ ObjectFile<E> *read_lto_object(Context<E> &ctx, MappedFile *mf) {
|
||||
i64 len = strlen(psym.name);
|
||||
memcpy(strtab.data() + strtab_offset, psym.name, len);
|
||||
strtab_offset += len + 1;
|
||||
|
||||
// comdat_key is non-null if the symbol is defined in a comdat member
|
||||
// section. We handle such symbols differently than comdat symbols in
|
||||
// a regular file because, unlike regular object files, IR files don't
|
||||
// have input sections.
|
||||
if (psym.comdat_key)
|
||||
obj->lto_comdat_groups[i + 1] = insert_comdat_group(ctx, psym.comdat_key);
|
||||
}
|
||||
|
||||
obj->symbol_strtab = save_string(ctx, strtab);
|
||||
|
||||
+16
-18
@@ -332,6 +332,10 @@ int mold_main(int argc, char **argv) {
|
||||
});
|
||||
}
|
||||
|
||||
// Handle -repro
|
||||
if (ctx.arg.repro)
|
||||
write_repro_file(ctx);
|
||||
|
||||
Timer t_before_copy(ctx, "before_copy");
|
||||
|
||||
// Apply -exclude-libs
|
||||
@@ -454,10 +458,6 @@ int mold_main(int argc, char **argv) {
|
||||
if (ctx.arg.print_dependencies)
|
||||
print_dependencies(ctx);
|
||||
|
||||
// Handle -repro
|
||||
if (ctx.arg.repro)
|
||||
write_repro_file(ctx);
|
||||
|
||||
// Handle --require-defined
|
||||
for (Symbol<E> *sym : ctx.arg.require_defined)
|
||||
if (!sym->file)
|
||||
@@ -480,16 +480,7 @@ int mold_main(int argc, char **argv) {
|
||||
shuffle_sections(ctx);
|
||||
|
||||
// Copy string referred by .dynamic to .dynstr.
|
||||
for (SharedFile<E> *file : ctx.dsos)
|
||||
ctx.dynstr->add_string(file->soname);
|
||||
for (std::string_view str : ctx.arg.auxiliary)
|
||||
ctx.dynstr->add_string(str);
|
||||
for (std::string_view str : ctx.arg.filter)
|
||||
ctx.dynstr->add_string(str);
|
||||
if (!ctx.arg.rpaths.empty())
|
||||
ctx.dynstr->add_string(ctx.arg.rpaths);
|
||||
if (!ctx.arg.soname.empty())
|
||||
ctx.dynstr->add_string(ctx.arg.soname);
|
||||
add_dynamic_strings(ctx);
|
||||
|
||||
if constexpr (is_ppc64v1<E>)
|
||||
ppc64v1_scan_symbols(ctx);
|
||||
@@ -534,10 +525,6 @@ int mold_main(int argc, char **argv) {
|
||||
// Fill .gnu.version_r section contents.
|
||||
ctx.verneed->construct(ctx);
|
||||
|
||||
// Compute .symtab and .strtab sizes for each file.
|
||||
if (!ctx.arg.strip_all)
|
||||
create_output_symtab(ctx);
|
||||
|
||||
// .eh_frame is a special section from the linker's point of view,
|
||||
// as its contents are parsed and reconstructed by the linker,
|
||||
// unlike other sections that are regarded as opaque bytes.
|
||||
@@ -549,6 +536,17 @@ int mold_main(int argc, char **argv) {
|
||||
if (ctx.arg.emit_relocs)
|
||||
create_reloc_sections(ctx);
|
||||
|
||||
// We've created range extension thunks with a pessimistive assumption
|
||||
// that all out-of-section references are out of range. Now that we are
|
||||
// able to assign addresses to all SHF_ALLOC output sections, we can
|
||||
// eliminate excessive thunks.
|
||||
if constexpr (needs_thunk<E>)
|
||||
remove_redundant_thunks(ctx);
|
||||
|
||||
// Compute .symtab and .strtab sizes for each file.
|
||||
if (!ctx.arg.strip_all)
|
||||
create_output_symtab(ctx);
|
||||
|
||||
// Compute the section header values for all sections.
|
||||
compute_section_headers(ctx);
|
||||
|
||||
|
||||
+2
-4
@@ -35,10 +35,8 @@ static Map<E> get_map(Context<E> &ctx) {
|
||||
return map;
|
||||
|
||||
tbb::parallel_for(map.range(), [](const typename Map<E>::range_type &range) {
|
||||
for (auto it = range.begin(); it != range.end(); it++) {
|
||||
std::vector<Symbol<E> *> &vec = it->second;
|
||||
sort(vec, [](Symbol<E> *a, Symbol<E> *b) { return a->value < b->value; });
|
||||
}
|
||||
for (auto &[k, v] : range)
|
||||
ranges::stable_sort(v, {}, &Symbol<E>::value);
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
+48
-14
@@ -155,6 +155,9 @@ static consteval i64 get_branch_distance() {
|
||||
template <needs_thunk E>
|
||||
static constexpr i64 branch_distance = get_branch_distance<E>() - 32;
|
||||
|
||||
template <needs_thunk E>
|
||||
void remove_redundant_thunks(Context<E> &ctx);
|
||||
|
||||
template <needs_thunk E>
|
||||
void gather_thunk_addresses(Context<E> &ctx);
|
||||
|
||||
@@ -259,9 +262,9 @@ struct FdeRecord {
|
||||
template <typename E>
|
||||
struct InputSectionExtras {};
|
||||
|
||||
template <typename E> requires is_arm32<E>
|
||||
struct InputSectionExtras<E> {
|
||||
InputSection<E> *exidx = nullptr;
|
||||
template <>
|
||||
struct InputSectionExtras<ARM32> {
|
||||
InputSection<ARM32> *exidx = nullptr;
|
||||
};
|
||||
|
||||
struct RelocDelta {
|
||||
@@ -308,6 +311,7 @@ public:
|
||||
bool is_relr_reloc(Context<E> &ctx, const ElfRel<E> &rel) const;
|
||||
bool icf_removed() const;
|
||||
bool record_undef_error(Context<E> &ctx, const ElfRel<E> &rel);
|
||||
void check_range(Context<E> &ctx, i64 i, i64 val, i64 lo, i64 hi);
|
||||
|
||||
std::pair<SectionFragment<E> *, i64>
|
||||
get_fragment(Context<E> &ctx, const ElfRel<E> &rel);
|
||||
@@ -566,7 +570,7 @@ public:
|
||||
void populate_symtab(Context<E> &ctx) override;
|
||||
|
||||
void scan_abs_relocations(Context<E> &ctx);
|
||||
void create_range_extension_thunks(Context<E> &ctx);
|
||||
void create_range_extension_thunks(Context<E> &ctx, bool first_pass);
|
||||
|
||||
std::vector<InputSection<E> *> members;
|
||||
std::vector<std::unique_ptr<Thunk<E>>> thunks;
|
||||
@@ -1324,7 +1328,6 @@ public:
|
||||
std::string_view get_string(Context<E> &ctx, const ElfShdr<E> &shdr);
|
||||
std::string_view get_string(Context<E> &ctx, i64 idx);
|
||||
u32 get_eflags() { return ((ElfEhdr<E> *)mf->data)->e_flags; }
|
||||
std::span<ElfPhdr<E>> get_phdrs();
|
||||
|
||||
ElfShdr<E> *find_section(i64 type);
|
||||
|
||||
@@ -1369,7 +1372,8 @@ protected:
|
||||
std::vector<Symbol<E>> frag_syms;
|
||||
};
|
||||
|
||||
template <typename E> struct ObjectFileExtras {};
|
||||
template <typename E>
|
||||
struct ObjectFileExtras {};
|
||||
|
||||
template <is_riscv E>
|
||||
struct ObjectFileExtras<E> {
|
||||
@@ -1418,6 +1422,7 @@ public:
|
||||
std::vector<bool> has_symver;
|
||||
std::vector<ComdatGroupRef<E>> comdat_groups;
|
||||
std::vector<InputSection<E> *> eh_frame_sections;
|
||||
std::vector<std::vector<ElfRel<E>>> decoded_crel;
|
||||
bool exclude_libs = false;
|
||||
std::map<u32, u32> gnu_properties;
|
||||
bool needs_executable_stack = false;
|
||||
@@ -1439,6 +1444,7 @@ public:
|
||||
|
||||
// For LTO
|
||||
std::vector<ElfSym<E>> lto_elf_syms;
|
||||
std::vector<ComdatGroup *> lto_comdat_groups;
|
||||
|
||||
private:
|
||||
void initialize_sections(Context<E> &ctx);
|
||||
@@ -1470,6 +1476,7 @@ public:
|
||||
std::span<Symbol<E> *> get_symbols_at(Symbol<E> *sym);
|
||||
i64 get_alignment(Symbol<E> *sym);
|
||||
std::vector<std::string_view> get_dt_needed(Context<E> &ctx);
|
||||
std::string_view get_dt_audit(Context<E> &ctx);
|
||||
bool is_readonly(Symbol<E> *sym);
|
||||
|
||||
void mark_live_objects(Context<E> &ctx,
|
||||
@@ -1672,6 +1679,7 @@ template <typename E> void sort_init_fini(Context<E> &);
|
||||
template <typename E> void sort_ctor_dtor(Context<E> &);
|
||||
template <typename E> void fixup_ctors_in_init_array(Context<E> &);
|
||||
template <typename E> void shuffle_sections(Context<E> &);
|
||||
template <typename E> void add_dynamic_strings(Context<E> &);
|
||||
template <typename E> void compute_section_sizes(Context<E> &);
|
||||
template <typename E> void sort_output_sections(Context<E> &);
|
||||
template <typename E> void claim_unresolved_symbols(Context<E> &);
|
||||
@@ -1800,6 +1808,12 @@ public:
|
||||
|
||||
template <> u64 get_eflags(Context<PPC64V2> &ctx);
|
||||
|
||||
//
|
||||
// arch-arc.cc
|
||||
//
|
||||
|
||||
template <> u64 get_eflags(Context<ARC> &ctx);
|
||||
|
||||
//
|
||||
// main.cc
|
||||
//
|
||||
@@ -1920,7 +1934,7 @@ struct ContextExtras<SPARC64> {
|
||||
template <typename E>
|
||||
struct Context {
|
||||
Context() {
|
||||
arg.entry = get_symbol(*this, "_start");
|
||||
arg.entry = get_symbol(*this, is_arc<E> ? "__start" : "_start");
|
||||
arg.fini = get_symbol(*this, "_fini");
|
||||
arg.init = get_symbol(*this, "_init");
|
||||
|
||||
@@ -2033,8 +2047,11 @@ struct Context {
|
||||
i64 z_stack_size = 0;
|
||||
std::optional<Glob> unique;
|
||||
std::optional<u64> physical_image_base;
|
||||
std::optional<std::vector<Symbol<E> *>> retain_symbols_file;
|
||||
std::string Map;
|
||||
std::string audit;
|
||||
std::string chroot;
|
||||
std::string depaudit;
|
||||
std::string dependency_file;
|
||||
std::string directory;
|
||||
std::string dynamic_linker;
|
||||
@@ -2046,7 +2063,6 @@ struct Context {
|
||||
std::string soname;
|
||||
std::string sysroot;
|
||||
std::string_view emulation;
|
||||
std::optional<std::vector<Symbol<E> *>> retain_symbols_file;
|
||||
std::unordered_map<std::string_view, u64> section_align;
|
||||
std::unordered_map<std::string_view, u64> section_start;
|
||||
std::unordered_set<std::string_view> discard_section;
|
||||
@@ -2502,6 +2518,9 @@ Symbol<E> *get_symbol(Context<E> &ctx, std::string_view key,
|
||||
template <typename E>
|
||||
Symbol<E> *get_symbol(Context<E> &ctx, std::string_view name);
|
||||
|
||||
template <typename E>
|
||||
ComdatGroup *insert_comdat_group(Context<E> &ctx, std::string_view name);
|
||||
|
||||
template <typename E>
|
||||
std::string_view demangle(const Symbol<E> &sym);
|
||||
|
||||
@@ -2573,7 +2592,11 @@ template <typename E>
|
||||
inline std::span<ElfRel<E>> InputSection<E>::get_rels(Context<E> &ctx) const {
|
||||
if (relsec_idx == -1)
|
||||
return {};
|
||||
return file.template get_data<ElfRel<E>>(ctx, file.elf_sections[relsec_idx]);
|
||||
|
||||
ElfShdr<E> &shdr = file.elf_sections[relsec_idx];
|
||||
if (shdr.sh_type == SHT_CREL)
|
||||
return file.decoded_crel[relsec_idx];
|
||||
return file.template get_data<ElfRel<E>>(ctx, shdr);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@@ -2648,13 +2671,24 @@ inline bool InputSection<E>::icf_removed() const {
|
||||
return this->leader && this->leader != this;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
inline void
|
||||
InputSection<E>::check_range(Context<E> &ctx, i64 i, i64 val, i64 lo, i64 hi) {
|
||||
if (val < lo || hi <= val) {
|
||||
const ElfRel<E> &rel = get_rels(ctx)[i];
|
||||
Symbol<E> &sym = *file.symbols[rel.r_sym];
|
||||
Error(ctx) << *this << ": relocation " << rel << " against "
|
||||
<< sym << " out of range: " << val << " is not in ["
|
||||
<< lo << ", " << hi << ")";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
std::pair<SectionFragment<E> *, i64>
|
||||
MergeableSection<E>::get_fragment(i64 offset) {
|
||||
std::span<u32> vec = frag_offsets;
|
||||
auto it = std::upper_bound(vec.begin(), vec.end(), offset);
|
||||
i64 idx = it - 1 - vec.begin();
|
||||
return {fragments[idx], offset - vec[idx]};
|
||||
auto it = ranges::upper_bound(frag_offsets, offset);
|
||||
i64 idx = it - 1 - frag_offsets.begin();
|
||||
return {fragments[idx], offset - frag_offsets[idx]};
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@@ -2988,7 +3022,7 @@ u64
|
||||
Symbol<E>::get_thunk_addr(Context<E> &ctx, u64 P) const requires needs_thunk<E> {
|
||||
std::span<u64> vec = ctx.symbol_aux[aux_idx].thunk_addrs;
|
||||
u64 lo = (P < branch_distance<E>) ? 0 : P - branch_distance<E>;
|
||||
u64 val = *std::lower_bound(vec.begin(), vec.end(), lo);
|
||||
u64 val = *ranges::lower_bound(vec, lo);
|
||||
i64 disp = val - P;
|
||||
if (disp < -branch_distance<E> || branch_distance<E> <= disp)
|
||||
Fatal(ctx) << "range extension thunk out of range: " << *this;
|
||||
|
||||
+63
-51
@@ -203,9 +203,7 @@ static std::vector<ElfPhdr<E>> create_phdr(Context<E> &ctx) {
|
||||
// The ELF spec says that "loadable segment entries in the program
|
||||
// header table appear in ascending order, sorted on the p_vaddr
|
||||
// member".
|
||||
sort(chunks, [](Chunk<E> *a, Chunk<E> *b) {
|
||||
return a->shdr.sh_addr < b->shdr.sh_addr;
|
||||
});
|
||||
ranges::stable_sort(chunks, {}, [](Chunk<E> *x) { return x->shdr.sh_addr; });
|
||||
|
||||
// Create a PT_PHDR for the program header itself.
|
||||
if (ctx.phdr && (ctx.phdr->shdr.sh_flags & SHF_ALLOC))
|
||||
@@ -657,6 +655,12 @@ static std::vector<Word<E>> create_dynamic_section(Context<E> &ctx) {
|
||||
for (std::string_view str : ctx.arg.auxiliary)
|
||||
define(DT_AUXILIARY, ctx.dynstr->find_string(str));
|
||||
|
||||
if (!ctx.arg.audit.empty())
|
||||
define(DT_AUDIT, ctx.dynstr->find_string(ctx.arg.audit));
|
||||
|
||||
if (!ctx.arg.depaudit.empty())
|
||||
define(DT_DEPAUDIT, ctx.dynstr->find_string(ctx.arg.depaudit));
|
||||
|
||||
for (std::string_view str : ctx.arg.filter)
|
||||
define(DT_FILTER, ctx.dynstr->find_string(str));
|
||||
|
||||
@@ -861,6 +865,7 @@ void OutputSection<E>::compute_section_size(Context<E> &ctx) {
|
||||
std::span<InputSection<E> *> members;
|
||||
i64 size = 0;
|
||||
i64 offset = 0;
|
||||
i64 align = 1;
|
||||
};
|
||||
|
||||
std::vector<Group> groups;
|
||||
@@ -872,26 +877,28 @@ void OutputSection<E>::compute_section_size(Context<E> &ctx) {
|
||||
m = m.subspan(sz);
|
||||
}
|
||||
|
||||
tbb::parallel_for_each(groups, [](Group &group) {
|
||||
tbb::parallel_for_each(groups, [](Group &g) {
|
||||
i64 off = 0;
|
||||
for (InputSection<E> *isec : group.members)
|
||||
for (InputSection<E> *isec : g.members) {
|
||||
off = align_to(off, 1 << isec->p2align) + isec->sh_size;
|
||||
group.size = off;
|
||||
g.align = std::max<i64>(g.align, 1 << isec->p2align);
|
||||
}
|
||||
g.size = off;
|
||||
});
|
||||
|
||||
i64 off = 0;
|
||||
for (i64 i = 0; i < groups.size(); i++) {
|
||||
off = align_to(off, shdr.sh_addralign);
|
||||
groups[i].offset = off;
|
||||
off += groups[i].size;
|
||||
for (Group &g : groups) {
|
||||
off = align_to(off, g.align);
|
||||
g.offset = off;
|
||||
off += g.size;
|
||||
}
|
||||
|
||||
shdr.sh_size = off;
|
||||
|
||||
// Assign offsets to input sections.
|
||||
tbb::parallel_for_each(groups, [](Group &group) {
|
||||
i64 off = group.offset;
|
||||
for (InputSection<E> *isec : group.members) {
|
||||
tbb::parallel_for_each(groups, [](Group &g) {
|
||||
i64 off = g.offset;
|
||||
for (InputSection<E> *isec : g.members) {
|
||||
off = align_to(off, 1 << isec->p2align);
|
||||
isec->offset = off;
|
||||
off += isec->sh_size;
|
||||
@@ -928,7 +935,7 @@ void OutputSection<E>::copy_buf(Context<E> &ctx) {
|
||||
P -= delta;
|
||||
}
|
||||
|
||||
auto dynrel = [&](i64 ty, i64 idx, u64 val) {
|
||||
auto write = [&](i64 ty, i64 idx, u64 val) {
|
||||
*rel++ = ElfRel<E>(P, ty, idx, val);
|
||||
if (ctx.arg.apply_dynamic_relocs)
|
||||
*(Word<E> *)loc = val;
|
||||
@@ -940,14 +947,14 @@ void OutputSection<E>::copy_buf(Context<E> &ctx) {
|
||||
*(Word<E> *)loc = S + A;
|
||||
break;
|
||||
case ABS_REL_BASEREL:
|
||||
dynrel(E::R_RELATIVE, 0, S + A);
|
||||
write(E::R_RELATIVE, 0, S + A);
|
||||
break;
|
||||
case ABS_REL_IFUNC:
|
||||
if constexpr (supports_ifunc<E>)
|
||||
dynrel(E::R_IRELATIVE, 0, sym.get_addr(ctx, NO_PLT) + A);
|
||||
write(E::R_IRELATIVE, 0, sym.get_addr(ctx, NO_PLT) + A);
|
||||
break;
|
||||
case ABS_REL_DYNREL:
|
||||
dynrel(E::R_ABS, sym.get_dynsym_idx(ctx), A);
|
||||
write(E::R_ABS, sym.get_dynsym_idx(ctx), A);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1008,9 +1015,8 @@ void OutputSection<E>::write_to(Context<E> &ctx, u8 *buf) {
|
||||
// the .rel.dyn section). A bitmap has LSB 1.
|
||||
template <typename E>
|
||||
static std::vector<u64> encode_relr(std::span<u64> pos) {
|
||||
assert(std::all_of(pos.begin(), pos.end(),
|
||||
[](u64 x) { return x % sizeof(Word<E>) == 0; }));
|
||||
assert(std::is_sorted(pos.begin(), pos.end()));
|
||||
assert(ranges::all_of(pos, [](u64 x) { return x % sizeof(Word<E>) == 0; }));
|
||||
assert(ranges::is_sorted(pos));
|
||||
|
||||
std::vector<u64> vec;
|
||||
i64 num_bits = E::is_64 ? 63 : 31;
|
||||
@@ -1051,6 +1057,16 @@ static AbsRelKind get_abs_rel_kind(Context<E> &ctx, Symbol<E> &sym) {
|
||||
return ABS_REL_DYNREL;
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
static bool is_absrel(const ElfRel<E> &r) {
|
||||
// On ARM32, R_ARM_TARGET1 is typically used for entries in .init_array
|
||||
// and is interpreted as either ABS32 or REL32 depending on the target.
|
||||
// All targets we support handle it as if it were a ABS32.
|
||||
if constexpr (is_arm32<E>)
|
||||
return r.r_type == E::R_ABS || r.r_type == R_ARM_TARGET1;
|
||||
return r.r_type == E::R_ABS;
|
||||
}
|
||||
|
||||
// Scan word-size absolute relocations (e.g. R_X86_64_64). This is
|
||||
// separated from scan_relocations() because only such relocations can
|
||||
// be promoted to dynamic relocations.
|
||||
@@ -1062,7 +1078,7 @@ void OutputSection<E>::scan_abs_relocations(Context<E> &ctx) {
|
||||
tbb::parallel_for((i64)0, (i64)members.size(), [&](i64 i) {
|
||||
InputSection<E> *isec = members[i];
|
||||
for (const ElfRel<E> &r : isec->get_rels(ctx))
|
||||
if (r.r_type == E::R_ABS)
|
||||
if (is_absrel(r))
|
||||
shards[i].push_back(AbsRel<E>{isec, r.r_offset, isec->file.symbols[r.r_sym],
|
||||
get_addend(*isec, r)});
|
||||
});
|
||||
@@ -1420,23 +1436,20 @@ void GotSection<E>::copy_buf(Context<E> &ctx) {
|
||||
ent.sym ? ent.sym->get_dynsym_idx(ctx) : 0,
|
||||
ent.val);
|
||||
|
||||
// A single TLSDESC relocation fixes two consecutive GOT slots
|
||||
// where one slot holds a function pointer and the other an
|
||||
// argument to the function. An addend should be applied not to
|
||||
// the function pointer but to the function argument, which is
|
||||
// usually stored to the second slot.
|
||||
//
|
||||
// ARM32 employs the inverted layout for some reason, so an
|
||||
// addend is applied to the first slot.
|
||||
bool is_tlsdesc = false;
|
||||
if constexpr (supports_tlsdesc<E> && !is_arm32<E>)
|
||||
is_tlsdesc = (ent.r_type == E::R_TLSDESC);
|
||||
|
||||
if (ctx.arg.apply_dynamic_relocs) {
|
||||
if (is_tlsdesc)
|
||||
buf[ent.idx + 1] = ent.val;
|
||||
else
|
||||
buf[ent.idx] = ent.val;
|
||||
// A single TLSDESC relocation fixes two consecutive GOT slots
|
||||
// where one slot holds a function pointer and the other an
|
||||
// argument to the function. An addend should be applied not to
|
||||
// the function pointer but to the function argument, which is
|
||||
// usually stored to the second slot.
|
||||
//
|
||||
// ARM32 employs the inverted layout for some reason, so an
|
||||
// addend is applied to the first slot.
|
||||
i64 i = ent.idx;
|
||||
if constexpr (supports_tlsdesc<E> && !is_arm32<E>)
|
||||
if (ent.r_type == E::R_TLSDESC)
|
||||
i = ent.idx + 1;
|
||||
buf[i] = ent.val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1718,8 +1731,9 @@ static u64 get_symbol_size(Symbol<E> &sym) {
|
||||
if constexpr (is_riscv<E> || is_loongarch<E>)
|
||||
if (esym.st_size)
|
||||
if (InputSection<E> *isec = sym.get_input_section())
|
||||
return esym.st_size + esym.st_value - sym.value -
|
||||
get_r_delta(*isec, esym.st_value + esym.st_size);
|
||||
if (isec->shdr().sh_flags & SHF_EXECINSTR)
|
||||
return esym.st_size + esym.st_value - sym.value -
|
||||
get_r_delta(*isec, esym.st_value + esym.st_size);
|
||||
return esym.st_size;
|
||||
}
|
||||
|
||||
@@ -2538,9 +2552,8 @@ void VerneedSection<E>::construct(Context<E> &ctx) {
|
||||
if (syms.empty())
|
||||
return;
|
||||
|
||||
sort(syms, [](Symbol<E> *a, Symbol<E> *b) {
|
||||
return std::tuple(((SharedFile<E> *)a->file)->soname, a->ver_idx) <
|
||||
std::tuple(((SharedFile<E> *)b->file)->soname, b->ver_idx);
|
||||
ranges::stable_sort(syms, {}, [](Symbol<E> *x) {
|
||||
return std::tuple{((SharedFile<E> *)x->file)->soname, x->ver_idx};
|
||||
});
|
||||
|
||||
// Resize .gnu.version
|
||||
@@ -2625,10 +2638,9 @@ void VerdefSection<E>::construct(Context<E> &ctx) {
|
||||
ctx.versym->contents.resize(ctx.dynsym->symbols.size(), VER_NDX_GLOBAL);
|
||||
ctx.versym->contents[0] = VER_NDX_LOCAL;
|
||||
|
||||
for (i64 i = 1; i < ctx.dynsym->symbols.size(); i++)
|
||||
if (Symbol<E> &sym = *ctx.dynsym->symbols[i];
|
||||
!sym.file->is_dso && sym.ver_idx != VER_NDX_UNSPECIFIED)
|
||||
ctx.versym->contents[sym.get_dynsym_idx(ctx)] = sym.ver_idx;
|
||||
for (Symbol<E> *sym : ctx.dynsym->symbols)
|
||||
if (sym && !sym->file->is_dso && sym->ver_idx != VER_NDX_UNSPECIFIED)
|
||||
ctx.versym->contents[sym->get_dynsym_idx(ctx)] = sym->ver_idx;
|
||||
|
||||
// Allocate a buffer for .gnu.version_d and write to it
|
||||
contents.resize((sizeof(ElfVerdef<E>) + sizeof(ElfVerdaux<E>)) *
|
||||
@@ -2738,10 +2750,6 @@ void NotePropertySection<E>::update_shdr(Context<E> &ctx) {
|
||||
std::map<u32, u32> map;
|
||||
|
||||
for (u32 key : keys) {
|
||||
auto has_key = [&](ObjectFile<E> *file) {
|
||||
return file->gnu_properties.contains(key);
|
||||
};
|
||||
|
||||
if (GNU_PROPERTY_X86_UINT32_AND_LO <= key &&
|
||||
key <= GNU_PROPERTY_X86_UINT32_AND_HI) {
|
||||
// An AND feature is set if all input objects have the property and
|
||||
@@ -2758,7 +2766,11 @@ void NotePropertySection<E>::update_shdr(Context<E> &ctx) {
|
||||
key <= GNU_PROPERTY_X86_UINT32_OR_AND_HI) {
|
||||
// An OR-AND feature is set if all input object files have the property
|
||||
// and some of them has the feature.
|
||||
if (std::all_of(files.begin(), files.end(), has_key))
|
||||
auto has_key = [&](ObjectFile<E> *file) {
|
||||
return file->gnu_properties.contains(key);
|
||||
};
|
||||
|
||||
if (ranges::all_of(files, has_key))
|
||||
for (ObjectFile<E> *file : files)
|
||||
map[key] |= get_value(file, key);
|
||||
}
|
||||
|
||||
+118
-96
@@ -56,6 +56,8 @@ int redo_main(Context<E> &ctx, int argc, char **argv) {
|
||||
return mold_main<LOONGARCH32>(argc, argv);
|
||||
if (target == LOONGARCH64::name)
|
||||
return mold_main<LOONGARCH64>(argc, argv);
|
||||
if (target == ARC::name)
|
||||
return mold_main<ARC>(argc, argv);
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -230,6 +232,45 @@ static void mark_live_objects(Context<E> &ctx) {
|
||||
});
|
||||
}
|
||||
|
||||
// Symbol resolution involving a default symbol version is tricky because
|
||||
// a symbol that provides the default version has two names by which it
|
||||
// can be referred. Specifically, a symbol `foo` with the default version
|
||||
// `VER1` can be referred to either as `foo` or `foo@VER1`. No other
|
||||
// symbols have two names like that.
|
||||
//
|
||||
// By default, we insert symbols with a default version without an at-sign
|
||||
// (i.e. `foo` instead of `foo@VER1`) into our internal symbol table.
|
||||
// Therefore, if the symbol is referenced with an at-sign (i.e.
|
||||
// `foo@VER1`), the reference fails to resolve. This function corrects
|
||||
// that error.
|
||||
//
|
||||
// In this function, we check all unresolved versioned symbols of the form
|
||||
// `foo@VER1` by removing the version part and see if `foo` has version
|
||||
// `VER1`. If it does, that's the symbol we are looking for.
|
||||
template <typename E>
|
||||
static void resolve_default_symver(Context<E> &ctx) {
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
for (i64 i = file->first_global; i < file->elf_syms.size(); i++) {
|
||||
const ElfSym<E> &esym = file->elf_syms[i];
|
||||
Symbol<E> &sym = *file->symbols[i];
|
||||
|
||||
if (!sym.file && esym.is_undef() &&
|
||||
file->has_symver[i - file->first_global]) {
|
||||
std::string_view str = file->symbol_strtab.data() + esym.st_name;
|
||||
i64 pos = str.find('@');
|
||||
assert(pos != str.npos);
|
||||
|
||||
std::string_view name = str.substr(0, pos);
|
||||
std::string_view ver = str.substr(pos + 1);
|
||||
|
||||
Symbol<E> *sym2 = get_symbol(ctx, name);
|
||||
if (sym2->file && sym2->file->is_dso && sym2->get_version() == ver)
|
||||
file->symbols[i] = sym2;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
static void clear_symbols(Context<E> &ctx) {
|
||||
std::vector<InputFile<E> *> files;
|
||||
@@ -268,6 +309,7 @@ void resolve_symbols(Context<E> &ctx) {
|
||||
file->resolve_symbols(ctx);
|
||||
});
|
||||
|
||||
resolve_default_symver(ctx);
|
||||
mark_live_objects(ctx);
|
||||
|
||||
// Now that we know the exact set of input files that are to be
|
||||
@@ -288,9 +330,13 @@ void resolve_symbols(Context<E> &ctx) {
|
||||
// we could eliminate a symbol that is already resolved to and cause
|
||||
// dangling references.
|
||||
tbb::parallel_for_each(ctx.objs, [](ObjectFile<E> *file) {
|
||||
if (file->is_reachable)
|
||||
if (file->is_reachable) {
|
||||
for (ComdatGroupRef<E> &ref : file->comdat_groups)
|
||||
update_minimum(ref.group->owner, file->priority);
|
||||
for (ComdatGroup *g : file->lto_comdat_groups)
|
||||
if (g)
|
||||
update_minimum(g->owner, file->priority);
|
||||
}
|
||||
});
|
||||
|
||||
tbb::parallel_for_each(ctx.objs, [](ObjectFile<E> *file) {
|
||||
@@ -339,7 +385,6 @@ void do_lto(Context<E> &ctx) {
|
||||
|
||||
// The compiler backend needs to know how symbols are resolved, so
|
||||
// compute symbol visibility, import/export bits, etc early.
|
||||
mark_live_objects(ctx);
|
||||
apply_version_script(ctx);
|
||||
parse_symbol_version(ctx);
|
||||
compute_import_export(ctx);
|
||||
@@ -374,9 +419,6 @@ void parse_eh_frame_sections(Context<E> &ctx) {
|
||||
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
file->parse_ehframe(ctx);
|
||||
|
||||
for (InputSection<E> *isec : file->eh_frame_sections)
|
||||
isec->is_alive = false;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -411,13 +453,9 @@ void convert_common_symbols(Context<E> &ctx) {
|
||||
|
||||
template <typename E>
|
||||
static bool has_ctors_and_init_array(Context<E> &ctx) {
|
||||
bool x = false;
|
||||
bool y = false;
|
||||
for (ObjectFile<E> *file : ctx.objs) {
|
||||
x |= file->has_ctors;
|
||||
y |= file->has_init_array;
|
||||
}
|
||||
return x && y;
|
||||
return
|
||||
ranges::any_of(ctx.objs, [](ObjectFile<E> *x) { return x->has_ctors; }) &&
|
||||
ranges::any_of(ctx.objs, [](ObjectFile<E> *x) { return x->has_init_array; });
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@@ -440,7 +478,6 @@ static u64 canonicalize_type(std::string_view name, u64 type) {
|
||||
if constexpr (is_x86_64<E>)
|
||||
if (type == SHT_X86_64_UNWIND)
|
||||
return SHT_PROGBITS;
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -894,8 +931,7 @@ void check_cet_errors(Context<E> &ctx) {
|
||||
assert(warning || ctx.arg.z_cet_report == CET_REPORT_ERROR);
|
||||
|
||||
auto has_feature = [](ObjectFile<E> *file, u32 feature) {
|
||||
return std::any_of(file->gnu_properties.begin(), file->gnu_properties.end(),
|
||||
[&](std::pair<u32, u32> kv) {
|
||||
return ranges::any_of(file->gnu_properties, [&](std::pair<u32, u32> kv) {
|
||||
return kv.first == GNU_PROPERTY_X86_FEATURE_1_AND &&
|
||||
(kv.second & feature);
|
||||
});
|
||||
@@ -991,7 +1027,7 @@ static std::string create_response_file(Context<E> &ctx) {
|
||||
|
||||
if (cwd != "/") {
|
||||
out << "--chroot ..";
|
||||
i64 depth = std::count(cwd.begin(), cwd.end(), '/');
|
||||
i64 depth = ranges::count(cwd, '/');
|
||||
for (i64 i = 1; i < depth; i++)
|
||||
out << "/..";
|
||||
out << "\n";
|
||||
@@ -1056,6 +1092,13 @@ void check_duplicate_symbols(Context<E> &ctx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if the symbol is a deduplicated comdat symbol that is in
|
||||
// an IR file.
|
||||
if (file->is_lto_obj)
|
||||
if (ComdatGroup *g = file->lto_comdat_groups[i])
|
||||
if (g->owner != file->priority)
|
||||
continue;
|
||||
|
||||
Error(ctx) << "duplicate symbol: " << *file << ": " << *sym.file
|
||||
<< ": " << sym;
|
||||
}
|
||||
@@ -1086,7 +1129,7 @@ void check_shlib_undefined(Context<E> &ctx) {
|
||||
|
||||
// Obtain a list of known shared library names.
|
||||
std::unordered_set<std::string_view> sonames;
|
||||
for (SharedFile<E> *file : ctx.dsos)
|
||||
for (std::unique_ptr<SharedFile<E>> &file : ctx.dso_pool)
|
||||
sonames.insert(file->soname);
|
||||
|
||||
tbb::parallel_for_each(ctx.dsos, [&](SharedFile<E> *file) {
|
||||
@@ -1207,7 +1250,7 @@ void sort_init_fini(Context<E> &ctx) {
|
||||
if (osec->name == ".init_array" || osec->name == ".preinit_array" ||
|
||||
osec->name == ".fini_array") {
|
||||
if (ctx.arg.shuffle_sections == SHUFFLE_SECTIONS_REVERSE)
|
||||
std::reverse(osec->members.begin(), osec->members.end());
|
||||
ranges::reverse(osec->members);
|
||||
|
||||
std::vector<Entry> vec;
|
||||
|
||||
@@ -1218,8 +1261,7 @@ void sort_init_fini(Context<E> &ctx) {
|
||||
else
|
||||
vec.push_back({isec, get_init_fini_priority(isec)});
|
||||
}
|
||||
|
||||
sort(vec, [](const Entry &a, const Entry &b) { return a.prio < b.prio; });
|
||||
ranges::stable_sort(vec, {}, &Entry::prio);
|
||||
|
||||
for (i64 i = 0; i < vec.size(); i++)
|
||||
osec->members[i] = vec[i].sect;
|
||||
@@ -1241,13 +1283,12 @@ void sort_ctor_dtor(Context<E> &ctx) {
|
||||
if (OutputSection<E> *osec = chunk->to_osec()) {
|
||||
if (osec->name == ".ctors" || osec->name == ".dtors") {
|
||||
if (ctx.arg.shuffle_sections != SHUFFLE_SECTIONS_REVERSE)
|
||||
std::reverse(osec->members.begin(), osec->members.end());
|
||||
ranges::reverse(osec->members);
|
||||
|
||||
std::vector<Entry> vec;
|
||||
for (InputSection<E> *isec : osec->members)
|
||||
vec.push_back({isec, get_ctor_dtor_priority(isec)});
|
||||
|
||||
sort(vec, [](const Entry &a, const Entry &b) { return a.prio < b.prio; });
|
||||
ranges::stable_sort(vec, {}, &Entry::prio);
|
||||
|
||||
for (i64 i = 0; i < vec.size(); i++)
|
||||
osec->members[i] = vec[i].sect;
|
||||
@@ -1281,9 +1322,7 @@ void fixup_ctors_in_init_array(Context<E> &ctx) {
|
||||
for (ElfRel<E> &r : rels)
|
||||
r.r_offset = isec.sh_size - r.r_offset - sizeof(Word<E>);
|
||||
|
||||
sort(rels, [](const ElfRel<E> &a, const ElfRel<E> &b) {
|
||||
return a.r_offset < b.r_offset;
|
||||
});
|
||||
ranges::stable_sort(rels, {}, &ElfRel<E>::r_offset);
|
||||
};
|
||||
|
||||
if (Chunk<E> *chunk = find_chunk(ctx, ".init_array"))
|
||||
@@ -1299,8 +1338,8 @@ void fixup_ctors_in_init_array(Context<E> &ctx) {
|
||||
reverse_contents(*isec);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void shuffle(std::vector<T> &vec, u64 seed) {
|
||||
template <typename E>
|
||||
static void shuffle(std::vector<InputSection<E> *> &vec, u64 seed) {
|
||||
if (vec.empty())
|
||||
return;
|
||||
|
||||
@@ -1353,7 +1392,7 @@ void shuffle_sections(Context<E> &ctx) {
|
||||
case SHUFFLE_SECTIONS_REVERSE:
|
||||
tbb::parallel_for_each(ctx.chunks, [&](Chunk<E> *chunk) {
|
||||
if (OutputSection<E> *osec = chunk->to_osec(); is_eligible(osec))
|
||||
std::reverse(osec->members.begin(), osec->members.end());
|
||||
ranges::reverse(osec->members);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
@@ -1361,6 +1400,35 @@ void shuffle_sections(Context<E> &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void add_dynamic_strings(Context<E> &ctx) {
|
||||
for (SharedFile<E> *file : ctx.dsos) {
|
||||
std::string_view s = file->get_dt_audit(ctx);
|
||||
if (!s.empty()) {
|
||||
if (!ctx.arg.depaudit.empty())
|
||||
ctx.arg.depaudit += ':';
|
||||
ctx.arg.depaudit += std::string(s);
|
||||
}
|
||||
}
|
||||
|
||||
auto add = [&](std::string_view s) {
|
||||
if (!s.empty())
|
||||
ctx.dynstr->add_string(s);
|
||||
};
|
||||
|
||||
for (SharedFile<E> *file : ctx.dsos)
|
||||
add(file->soname);
|
||||
for (std::string_view str : ctx.arg.auxiliary)
|
||||
add(str);
|
||||
for (std::string_view str : ctx.arg.filter)
|
||||
add(str);
|
||||
|
||||
add(ctx.arg.audit);
|
||||
add(ctx.arg.depaudit);
|
||||
add(ctx.arg.rpaths);
|
||||
add(ctx.arg.soname);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
void compute_section_sizes(Context<E> &ctx) {
|
||||
Timer t(ctx, "compute_section_sizes");
|
||||
@@ -1368,16 +1436,16 @@ void compute_section_sizes(Context<E> &ctx) {
|
||||
if constexpr (needs_thunk<E>) {
|
||||
std::vector<Chunk<E> *> vec = ctx.chunks;
|
||||
|
||||
auto mid = std::partition(vec.begin(), vec.end(), [&](Chunk<E> *chunk) {
|
||||
auto tail = ranges::partition(vec, [&](Chunk<E> *chunk) {
|
||||
return chunk->to_osec() && (chunk->shdr.sh_flags & SHF_EXECINSTR) &&
|
||||
!ctx.arg.relocatable;
|
||||
});
|
||||
|
||||
// create_range_extension_thunks is not thread-safe
|
||||
for (Chunk<E> *chunk : std::span(vec.begin(), mid))
|
||||
chunk->to_osec()->create_range_extension_thunks(ctx);
|
||||
for (Chunk<E> *chunk : std::span(vec.begin(), tail.begin()))
|
||||
chunk->to_osec()->create_range_extension_thunks(ctx, true);
|
||||
|
||||
tbb::parallel_for_each(mid, vec.end(), [&](Chunk<E> *chunk) {
|
||||
tbb::parallel_for_each(tail, [&](Chunk<E> *chunk) {
|
||||
chunk->compute_section_size(ctx);
|
||||
});
|
||||
} else {
|
||||
@@ -1413,24 +1481,6 @@ void claim_unresolved_symbols(Context<E> &ctx) {
|
||||
if (!sym.esym().is_undef() || sym.file->priority <= file->priority)
|
||||
continue;
|
||||
|
||||
// If a symbol name is in the form of "foo@version", search for
|
||||
// symbol "foo" and check if the symbol has version "version".
|
||||
if (file->has_symver[i - file->first_global]) {
|
||||
std::string_view str = file->symbol_strtab.data() + esym.st_name;
|
||||
i64 pos = str.find('@');
|
||||
assert(pos != str.npos);
|
||||
|
||||
std::string_view name = str.substr(0, pos);
|
||||
std::string_view ver = str.substr(pos + 1);
|
||||
|
||||
Symbol<E> *sym2 = get_symbol(ctx, name);
|
||||
if (sym2->file && sym2->file->is_dso && sym2->get_version() == ver) {
|
||||
file->symbols[i] = sym2;
|
||||
sym2->is_imported = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto claim = [&](bool is_imported) {
|
||||
if (sym.is_traced)
|
||||
Out(ctx) << "trace-symbol: " << *file << ": unresolved"
|
||||
@@ -1739,29 +1789,26 @@ void sort_dynsyms(Context<E> &ctx) {
|
||||
return;
|
||||
|
||||
// In any symtab, local symbols must precede global symbols.
|
||||
auto first_global = std::stable_partition(syms.begin() + 1, syms.end(),
|
||||
[&](Symbol<E> *sym) {
|
||||
auto globals = ranges::stable_partition(syms.subspan(1), [&](Symbol<E> *sym) {
|
||||
return sym->is_local(ctx);
|
||||
});
|
||||
|
||||
// .gnu.hash imposes more restrictions on the order of the symbols in
|
||||
// .dynsym.
|
||||
if (ctx.gnu_hash) {
|
||||
auto first_exported = std::stable_partition(first_global, syms.end(),
|
||||
[](Symbol<E> *sym) {
|
||||
auto exported_syms = ranges::stable_partition(globals, [](Symbol<E> *sym) {
|
||||
return !sym->is_exported;
|
||||
});
|
||||
|
||||
// Count the number of exported symbols to compute the size of .gnu.hash.
|
||||
i64 num_exported = syms.end() - first_exported;
|
||||
i64 num_exported = exported_syms.size();
|
||||
u32 num_buckets = num_exported / ctx.gnu_hash->LOAD_FACTOR + 1;
|
||||
|
||||
tbb::parallel_for_each(first_exported, syms.end(), [&](Symbol<E> *sym) {
|
||||
tbb::parallel_for_each(exported_syms, [&](Symbol<E> *sym) {
|
||||
sym->set_djb_hash(ctx, djb_hash(sym->name()));
|
||||
});
|
||||
|
||||
tbb::parallel_sort(first_exported, syms.end(),
|
||||
[&](Symbol<E> *a, Symbol<E> *b) {
|
||||
tbb::parallel_sort(exported_syms, [&](Symbol<E> *a, Symbol<E> *b) {
|
||||
return std::tuple(a->get_djb_hash(ctx) % num_buckets, a->name()) <
|
||||
std::tuple(b->get_djb_hash(ctx) % num_buckets, b->name());
|
||||
});
|
||||
@@ -1782,7 +1829,7 @@ void sort_dynsyms(Context<E> &ctx) {
|
||||
ctx.dynstr->shdr.sh_size += size.combine(std::plus());
|
||||
|
||||
// ELF's symbol table sh_info holds the offset of the first global symbol.
|
||||
ctx.dynsym->shdr.sh_info = first_global - syms.begin();
|
||||
ctx.dynsym->shdr.sh_info = globals.begin() - syms.begin();
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@@ -1828,8 +1875,7 @@ void apply_version_script(Context<E> &ctx) {
|
||||
// last one takes precedence.
|
||||
std::vector<VersionPattern> patterns = ctx.version_patterns;
|
||||
|
||||
std::stable_partition(patterns.begin(), patterns.end(),
|
||||
[](const VersionPattern &pat) {
|
||||
ranges::stable_partition(patterns, [](const VersionPattern &pat) {
|
||||
return pat.ver_idx == VER_NDX_LOCAL;
|
||||
});
|
||||
|
||||
@@ -1941,7 +1987,7 @@ void parse_symbol_version(Context<E> &ctx) {
|
||||
// versioned symbol. Likewise, if `foo@VERSION` and `foo@@VERSION` are
|
||||
// defined, the default one takes precedence.
|
||||
Symbol<E> *sym2 = get_symbol(ctx, sym->name());
|
||||
if (sym2->file == file &&
|
||||
if (sym2 != sym && sym2->file == file &&
|
||||
!file->has_symver[sym2->sym_idx - file->first_global])
|
||||
if (sym2->ver_idx == ctx.default_version ||
|
||||
(sym2->ver_idx & ~VERSYM_HIDDEN) == (sym->ver_idx & ~VERSYM_HIDDEN))
|
||||
@@ -2300,9 +2346,8 @@ void sort_output_sections_regular(Context<E> &ctx) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
sort(ctx.chunks, [&](Chunk<E> *a, Chunk<E> *b) {
|
||||
return std::tuple{get_rank1(a), get_rank2(a), a->name} <
|
||||
std::tuple{get_rank1(b), get_rank2(b), b->name};
|
||||
ranges::stable_sort(ctx.chunks, {}, [&](Chunk<E> *x) {
|
||||
return std::tuple{get_rank1(x), get_rank2(x), x->name};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2358,9 +2403,7 @@ void sort_output_sections_by_order(Context<E> &ctx) {
|
||||
chunk->sect_order = get_rank(chunk);
|
||||
|
||||
// Sort output sections by --section-order
|
||||
sort(ctx.chunks, [](Chunk<E> *a, Chunk<E> *b) {
|
||||
return a->sect_order < b->sect_order;
|
||||
});
|
||||
ranges::stable_sort(ctx.chunks, {}, &Chunk<E>::sect_order);
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@@ -2415,27 +2458,6 @@ static void set_virtual_addresses_regular(Context<E> &ctx) {
|
||||
std::vector<Chunk<E> *> &chunks = ctx.chunks;
|
||||
u64 addr = ctx.arg.image_base;
|
||||
|
||||
// TLS chunks alignments are special: in addition to having their virtual
|
||||
// addresses aligned, they also have to be aligned when the region of
|
||||
// tls_begin is copied to a new thread's storage area. In other words, their
|
||||
// offset against tls_begin also has to be aligned.
|
||||
//
|
||||
// A good way to achieve this is to take the largest alignment requirement
|
||||
// of all TLS sections and make tls_begin also aligned to that.
|
||||
Chunk<E> *first_tls_chunk = nullptr;
|
||||
u64 tls_alignment = 1;
|
||||
for (Chunk<E> *chunk : chunks) {
|
||||
if (chunk->shdr.sh_flags & SHF_TLS) {
|
||||
if (!first_tls_chunk)
|
||||
first_tls_chunk = chunk;
|
||||
tls_alignment = std::max(tls_alignment, (u64)chunk->shdr.sh_addralign);
|
||||
}
|
||||
}
|
||||
|
||||
auto alignment = [&](Chunk<E> *chunk) {
|
||||
return chunk == first_tls_chunk ? tls_alignment : (u64)chunk->shdr.sh_addralign;
|
||||
};
|
||||
|
||||
auto is_tbss = [](Chunk<E> *chunk) {
|
||||
return (chunk->shdr.sh_type == SHT_NOBITS) && (chunk->shdr.sh_flags & SHF_TLS);
|
||||
};
|
||||
@@ -2507,7 +2529,7 @@ static void set_virtual_addresses_regular(Context<E> &ctx) {
|
||||
if (is_tbss(chunks[i])) {
|
||||
u64 addr2 = addr;
|
||||
for (;;) {
|
||||
addr2 = align_to(addr2, alignment(chunks[i]));
|
||||
addr2 = align_to(addr2, chunks[i]->shdr.sh_addralign);
|
||||
chunks[i]->shdr.sh_addr = addr2;
|
||||
addr2 += chunks[i]->shdr.sh_size;
|
||||
if (i + 2 == chunks.size() || !is_tbss(chunks[i + 1]))
|
||||
@@ -2517,7 +2539,7 @@ static void set_virtual_addresses_regular(Context<E> &ctx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addr = align_to(addr, alignment(chunks[i]));
|
||||
addr = align_to(addr, chunks[i]->shdr.sh_addralign);
|
||||
chunks[i]->shdr.sh_addr = addr;
|
||||
addr += chunks[i]->shdr.sh_size;
|
||||
}
|
||||
@@ -2679,11 +2701,10 @@ void separate_debug_sections(Context<E> &ctx) {
|
||||
chunk->name.starts_with(".debug_");
|
||||
};
|
||||
|
||||
auto mid = std::stable_partition(ctx.chunks.begin(), ctx.chunks.end(),
|
||||
is_debug_section);
|
||||
auto tail = ranges::stable_partition(ctx.chunks, std::not_fn(is_debug_section));
|
||||
|
||||
ctx.debug_chunks = {ctx.chunks.begin(), mid};
|
||||
ctx.chunks.erase(ctx.chunks.begin(), mid);
|
||||
ctx.debug_chunks = {tail.begin(), tail.end()};
|
||||
ctx.chunks.erase(tail.begin(), tail.end());
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
@@ -3358,6 +3379,7 @@ template void sort_init_fini(Context<E> &);
|
||||
template void sort_ctor_dtor(Context<E> &);
|
||||
template void fixup_ctors_in_init_array(Context<E> &);
|
||||
template void shuffle_sections(Context<E> &);
|
||||
template void add_dynamic_strings(Context<E> &);
|
||||
template void compute_section_sizes(Context<E> &);
|
||||
template void sort_output_sections(Context<E> &);
|
||||
template void claim_unresolved_symbols(Context<E> &);
|
||||
|
||||
@@ -69,10 +69,8 @@ using E = MOLD_TARGET;
|
||||
template <>
|
||||
i64 get_r_delta(InputSection<E> &isec, u64 offset) {
|
||||
std::span<RelocDelta> deltas = isec.extra.r_deltas;
|
||||
auto it = std::upper_bound(deltas.begin(), deltas.end(), offset,
|
||||
[](u64 val, const RelocDelta &x) {
|
||||
return val <= x.offset;
|
||||
});
|
||||
auto it = ranges::upper_bound(deltas, offset, std::less_equal<>{},
|
||||
&RelocDelta::offset);
|
||||
return (it == deltas.begin()) ? 0 : (it - 1)->delta;
|
||||
}
|
||||
|
||||
@@ -101,8 +99,9 @@ void shrink_sections(Context<E> &ctx) {
|
||||
for (Symbol<E> *sym : file->symbols)
|
||||
if (sym->file == file)
|
||||
if (InputSection<E> *isec = sym->get_input_section())
|
||||
if (i64 delta = get_r_delta(*isec, sym->value))
|
||||
sym->value -= delta;
|
||||
if (isec->shdr().sh_flags & SHF_EXECINSTR)
|
||||
if (i64 delta = get_r_delta(*isec, sym->value))
|
||||
sym->value -= delta;
|
||||
});
|
||||
|
||||
// Recompute sizes of executable sections
|
||||
|
||||
+66
-48
@@ -45,44 +45,26 @@ static constexpr i64 max_thunk_size = 1024 * 1024;
|
||||
static constexpr i64 thunk_align = 16;
|
||||
|
||||
template <typename E>
|
||||
static bool is_reachable(Context<E> &ctx, InputSection<E> &isec,
|
||||
static bool is_reachable(Context<E> &ctx, bool first_pass, InputSection<E> &isec,
|
||||
Symbol<E> &sym, const ElfRel<E> &rel) {
|
||||
// We create thunks with a pessimistic assumption that all
|
||||
// out-of-section relocations would be out-of-range.
|
||||
InputSection<E> *isec2 = sym.get_input_section();
|
||||
if (!isec2 || isec.output_section != isec2->output_section)
|
||||
return false;
|
||||
|
||||
// Even if the target is the same section, we branch to its PLT
|
||||
// if it has one. So a symbol with a PLT is also considered an
|
||||
// out-of-section reference.
|
||||
if (sym.has_plt(ctx))
|
||||
return false;
|
||||
|
||||
// If the target section is in the same output section but
|
||||
// hasn't got any address yet, that's unreacahble.
|
||||
if (isec2->offset == -1)
|
||||
InputSection<E> *isec2 = sym.get_input_section();
|
||||
if (isec2 && isec.output_section == isec2->output_section &&
|
||||
isec2->offset == -1)
|
||||
return false;
|
||||
|
||||
// Thumb and ARM B instructions cannot be converted to BX, so we
|
||||
// always have to make them jump to a thunk to switch processor mode
|
||||
// even if their destinations are within their ranges.
|
||||
if constexpr (is_arm32<E>) {
|
||||
bool is_thumb = sym.get_addr(ctx) & 1;
|
||||
if ((rel.r_type == R_ARM_THM_JUMP24 && !is_thumb) ||
|
||||
(rel.r_type == R_ARM_JUMP24 && is_thumb) ||
|
||||
(rel.r_type == R_ARM_PLT32 && is_thumb))
|
||||
// We don't know about the final file layout on the first pass, so
|
||||
// we assume pessimistically that all out-of-section relocations are
|
||||
// out-of-range. Excessive thunks will be removed on the second pass.
|
||||
if (first_pass) {
|
||||
if (!isec2 || isec.output_section != isec2->output_section)
|
||||
return false;
|
||||
}
|
||||
|
||||
// PowerPC before Power9 lacks PC-relative load/store instructions.
|
||||
// Functions compiled for Power9 or earlier assume that r2 points to
|
||||
// GOT+0x8000, while those for Power10 uses r2 as a scratch register.
|
||||
// We need to a thunk to recompute r2 for interworking.
|
||||
if constexpr (is_ppc64v2<E>) {
|
||||
if (rel.r_type == R_PPC64_REL24 && !sym.esym().ppc64_preserves_r2())
|
||||
return false;
|
||||
if (rel.r_type == R_PPC64_REL24_NOTOC && sym.esym().ppc64_uses_toc())
|
||||
// Even if the target is the same section, we branch to its PLT
|
||||
// if it has one. So a symbol with a PLT is also considered an
|
||||
// out-of-section reference.
|
||||
if (sym.has_plt(ctx))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -95,13 +77,36 @@ static bool is_reachable(Context<E> &ctx, InputSection<E> &isec,
|
||||
return -branch_distance<E> <= val && val < branch_distance<E>;
|
||||
}
|
||||
|
||||
static void reset(Thunk<E> &thunk) {
|
||||
for (Symbol<E> *sym : thunk.symbols)
|
||||
sym->flags = 0;
|
||||
template <typename E>
|
||||
static bool needs_shim(Context<E> &ctx, Symbol<E> &sym, const ElfRel<E> &rel) {
|
||||
// Thumb and ARM B instructions cannot be converted to BX, so we
|
||||
// always have to make them jump to a thunk to switch processor mode
|
||||
// even if their destinations are within their ranges.
|
||||
if constexpr (is_arm32<E>) {
|
||||
bool is_thumb = sym.get_addr(ctx) & 1;
|
||||
return (rel.r_type == R_ARM_THM_JUMP24 && !is_thumb) ||
|
||||
(rel.r_type == R_ARM_JUMP24 && is_thumb) ||
|
||||
(rel.r_type == R_ARM_PLT32 && is_thumb);
|
||||
}
|
||||
|
||||
// On PowerPC, all PLT calls go through range extension thunks.
|
||||
if constexpr (is_ppc32<E> || is_ppc64v1<E>)
|
||||
return sym.has_plt(ctx);
|
||||
|
||||
// PowerPC before Power9 lacks PC-relative load/store instructions.
|
||||
// Functions compiled for Power9 or earlier assume that r2 points to
|
||||
// GOT+0x8000, while those for Power10 uses r2 as a scratch register.
|
||||
// We need to a thunk to recompute r2 for interworking.
|
||||
if constexpr (is_ppc64v2<E>)
|
||||
return sym.has_plt(ctx) ||
|
||||
(rel.r_type == R_PPC64_REL24 && !sym.esym().ppc64_preserves_r2()) ||
|
||||
(rel.r_type == R_PPC64_REL24_NOTOC && sym.esym().ppc64_uses_toc());
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx) {
|
||||
void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx,
|
||||
bool first_pass) {
|
||||
std::span<InputSection<E> *> m = members;
|
||||
if (m.empty())
|
||||
return;
|
||||
@@ -169,8 +174,9 @@ void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx) {
|
||||
a++;
|
||||
|
||||
// Erase references to out-of-range thunks.
|
||||
while (t < thunks.size() && thunks[t]->offset < m[a]->offset)
|
||||
reset(*thunks[t++]);
|
||||
for (; t < thunks.size() && thunks[t]->offset < m[a]->offset; t++)
|
||||
for (Symbol<E> *sym : thunks[t]->symbols)
|
||||
sym->flags = 0;
|
||||
|
||||
// Create a new thunk and place it at D.
|
||||
offset = align_to(offset, thunk_align);
|
||||
@@ -193,12 +199,12 @@ void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx) {
|
||||
if (!sym.file)
|
||||
continue;
|
||||
|
||||
// Skip if the destination is within reach.
|
||||
if (is_reachable(ctx, isec, sym, rel))
|
||||
// Skip if we can directly branch to the destination.
|
||||
if (is_reachable(ctx, first_pass, isec, sym, rel) &&
|
||||
!needs_shim(ctx, sym, rel))
|
||||
continue;
|
||||
|
||||
// Add the symbol to the current thunk if it's not added already
|
||||
// by other thread.
|
||||
// Add the symbol to the current thunk if it's not added already.
|
||||
if (!sym.flags.test_and_set()) {
|
||||
std::scoped_lock lock(mu);
|
||||
thunk.symbols.push_back(&sym);
|
||||
@@ -207,9 +213,8 @@ void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx) {
|
||||
});
|
||||
|
||||
// Sort symbols added to the thunk to make the output deterministic.
|
||||
sort(thunk.symbols, [](Symbol<E> *a, Symbol<E> *b) {
|
||||
return std::tuple{a->file->priority, a->sym_idx} <
|
||||
std::tuple{b->file->priority, b->sym_idx};
|
||||
ranges::sort(thunk.symbols, {}, [](Symbol<E> *x) {
|
||||
return std::tuple{x->file->priority, x->sym_idx};
|
||||
});
|
||||
|
||||
// Now that we know the number of symbols in the thunk, we can compute
|
||||
@@ -221,11 +226,24 @@ void OutputSection<E>::create_range_extension_thunks(Context<E> &ctx) {
|
||||
b = c;
|
||||
}
|
||||
|
||||
while (t < thunks.size())
|
||||
reset(*thunks[t++]);
|
||||
for (; t < thunks.size(); t++)
|
||||
for (Symbol<E> *sym : thunks[t]->symbols)
|
||||
sym->flags = 0;
|
||||
|
||||
this->shdr.sh_size = offset;
|
||||
}
|
||||
|
||||
template <>
|
||||
void remove_redundant_thunks(Context<E> &ctx) {
|
||||
Timer t(ctx, "remove_redundant_thunks");
|
||||
set_osec_offsets(ctx);
|
||||
|
||||
for (Chunk<E> *chunk : ctx.chunks)
|
||||
if (OutputSection<E> *osec = chunk->to_osec())
|
||||
if (osec->shdr.sh_flags & SHF_EXECINSTR)
|
||||
osec->create_range_extension_thunks(ctx, false);
|
||||
}
|
||||
|
||||
// When applying relocations, we want to know the address in a reachable
|
||||
// range extension thunk for a given symbol. Doing it by scanning all
|
||||
// reachable range extension thunks is too expensive.
|
||||
@@ -243,8 +261,8 @@ void gather_thunk_addresses(Context<E> &ctx) {
|
||||
if (OutputSection<E> *osec = chunk->to_osec())
|
||||
sections.push_back(osec);
|
||||
|
||||
sort(sections, [](OutputSection<E> *a, OutputSection<E> *b) {
|
||||
return a->shdr.sh_addr < b->shdr.sh_addr;
|
||||
ranges::stable_sort(sections, {}, [](OutputSection<E> *x) {
|
||||
return x->shdr.sh_addr;
|
||||
});
|
||||
|
||||
for (OutputSection<E> *osec : sections) {
|
||||
|
||||
+1
-1
@@ -162,7 +162,7 @@ u64 get_tp_addr(const ElfPhdr<E> &phdr) {
|
||||
// and %a0/%a1 on s390x) refers to past the end of the TLS block for
|
||||
// historical reasons. TLVs are accessed with negative offsets from TP.
|
||||
return align_to(phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
|
||||
} else if constexpr (is_arm<E> || is_sh4<E>) {
|
||||
} else if constexpr (is_arm<E> || is_sh4<E> || is_arc<E>) {
|
||||
// On ARM and SH4, the runtime appends two words at the beginning
|
||||
// of TLV template image when copying TLVs to the TLS block, so we need
|
||||
// to offset it.
|
||||
|
||||
+7
-2
@@ -31,7 +31,7 @@ endif()
|
||||
if(MOLD_ENABLE_QEMU_TESTS)
|
||||
list(APPEND QEMU_ARCHS
|
||||
x86_64 i386 arm aarch64 aarch64_be ppc ppc64 ppc64le sparc64 sh4 sh4eb
|
||||
s390x riscv64 riscv32 m68k loongarch64)
|
||||
s390x riscv64 riscv32 m68k loongarch64 arc)
|
||||
|
||||
LIST(APPEND TRIPLES
|
||||
x86_64-linux-gnu
|
||||
@@ -49,7 +49,8 @@ if(MOLD_ENABLE_QEMU_TESTS)
|
||||
sh4aeb-linux-gnu
|
||||
riscv32-linux-gnu
|
||||
m68k-linux-gnu
|
||||
loongarch64-linux-gnu)
|
||||
loongarch64-linux-gnu
|
||||
arc-linux-gnu)
|
||||
|
||||
foreach(ARCH IN LISTS QEMU_ARCHS)
|
||||
find_program(HAS_qemu-${ARCH} qemu-${ARCH})
|
||||
@@ -184,3 +185,7 @@ endif()
|
||||
if(${MACHINE} STREQUAL "loongarch64" OR (HAS_qemu-loongarch64 AND HAS_loongarch64-linux-gnu-gcc))
|
||||
add_target(loongarch64 loongarch64-linux-gnu)
|
||||
endif()
|
||||
|
||||
if(${MACHINE} STREQUAL "arc" OR (HAS_qemu-loongarch64 AND HAS_arc-linux-gnu-gcc))
|
||||
add_target(arc arc-linux-gnu)
|
||||
endif()
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -c -xc -
|
||||
int main() {}
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe1 $t/a.o
|
||||
readelf --dynamic $t/exe1 | not grep 'Audit library'
|
||||
|
||||
$CC -B. -o $t/exe2 $t/a.o -Wl,--audit=foo
|
||||
readelf --dynamic $t/exe2 | grep -F 'Audit library: [foo]'
|
||||
|
||||
$CC -B. -o $t/exe3 $t/a.o -Wl,--audit=foo -Wl,--audit=bar
|
||||
readelf --dynamic $t/exe3 | grep -F 'Audit library: [foo:bar]'
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
# Currently, CREL is not supported on REL-type targets
|
||||
[ $MACHINE = arm ] && skip
|
||||
[ $MACHINE = i686 ] && skip
|
||||
|
||||
[ "$CC" = cc ] || skip
|
||||
clang -c -xc -o /dev/null /dev/null -Wa,--crel,--allow-experimental-crel || skip
|
||||
|
||||
cat <<EOF | clang -o $t/a.o -c -xc - -Wa,--crel,--allow-experimental-crel
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
printf("Hello world\n");
|
||||
}
|
||||
EOF
|
||||
|
||||
clang -B. -o $t/exe $t/a.o
|
||||
$QEMU $t/exe | grep 'Hello world'
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -c -xc -
|
||||
int main() {}
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe1 $t/a.o
|
||||
readelf --dynamic $t/exe1 | not grep 'Dependency audit library'
|
||||
|
||||
$CC -B. -o $t/exe2 $t/a.o -Wl,--depaudit=libdepaudit.so
|
||||
readelf --dynamic $t/exe2 | grep -F 'Dependency audit library: [libdepaudit.so]'
|
||||
|
||||
$CC -B. -o $t/exe3 $t/a.o -Wl,--depaudit=foo -Wl,-P,bar
|
||||
readelf --dynamic $t/exe3 | grep -F 'Dependency audit library: [foo:bar]'
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<'EOF' | $CC -B. -shared -o $t/a.so -xc - -fPIC
|
||||
#include <stdio.h>
|
||||
|
||||
unsigned la_version(unsigned v) {
|
||||
fprintf(stderr, "version=%d\n", v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void foo() {}
|
||||
EOF
|
||||
|
||||
cat <<'EOF' | $CC -B. -shared -o $t/b.so -xc - -fPIC -Wl,--audit=$t/a.so
|
||||
void foo();
|
||||
void bar() { foo(); }
|
||||
EOF
|
||||
|
||||
cat <<'EOF' | $CC -c -o $t/c.o -xc -
|
||||
void bar();
|
||||
int main() { bar(); }
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe1 $t/c.o $t/b.so
|
||||
readelf --dynamic $t/exe1 | grep 'Dependency audit library:..*/a.so'
|
||||
|
||||
$CC -B. -o $t/exe2 $t/c.o $t/b.so -Wl,--depaudit=foo
|
||||
readelf --dynamic $t/exe2 | grep 'Dependency audit library:..*foo:.*/a.so'
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
[ $MACHINE = $(uname -m) ] || skip
|
||||
echo 'int main() {}' | clang -B. -flto -o /dev/null -xc - || skip
|
||||
|
||||
echo '' | clang -S -emit-llvm -flto -o $t/a.ll -xc - || skip
|
||||
|
||||
cat <<'EOF' >> $t/a.ll
|
||||
$foo = comdat any
|
||||
@foo = global i32 42, comdat($foo)
|
||||
EOF
|
||||
|
||||
cp $t/a.ll $t/b.ll
|
||||
|
||||
clang -S -emit-llvm -flto -o $t/a.bc $t/a.ll
|
||||
clang -S -emit-llvm -flto -o $t/b.bc $t/b.ll
|
||||
|
||||
cat <<'EOF' | clang -o $t/c.o -c -flto -xc -
|
||||
#include <stdio.h>
|
||||
extern int foo;
|
||||
int main() { printf("%d\n", foo); }
|
||||
EOF
|
||||
|
||||
clang -B. -o $t/exe -flto $t/a.bc $t/b.bc $t/c.o
|
||||
$QEMU $t/exe | grep 42
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
[ $MACHINE = $(uname -m) ] || skip
|
||||
|
||||
echo 'int main() {}' | clang -B. -flto -o /dev/null -xc - >& /dev/null || skip
|
||||
|
||||
cat <<EOF | clang -flto -c -o $t/a.o -xc -
|
||||
int main() {}
|
||||
EOF
|
||||
|
||||
clang -B. -o $t/exe1 -flto $t/a.o -Wl,-mllvm,-pass-remarks=.
|
||||
clang -B. -o $t/exe2 -flto $t/a.o -Wl,-plugin-opt,-pass-remarks=.
|
||||
|
||||
not clang -B. -o $t/exe3 -flto $t/a.o -Wl,-mllvm,--no-such-option |&
|
||||
grep -i 'Unknown command line argument'
|
||||
|
||||
not clang -B. -o $t/exe4 -flto $t/a.o -Wl,-plugin-opt,--no-such-option |&
|
||||
grep -i 'Unknown command line argument'
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<EOF | $CC -B. -shared -fPIC -o $t/libfoo.so -xc -
|
||||
void foo() {}
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CC -B. -shared -fPIC -o $t/libbar.so -xc - -L$t -lfoo
|
||||
void foo();
|
||||
void bar() { foo(); }
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CC -c -o $t/a.o -c -xc -
|
||||
int bar();
|
||||
int main() { bar(); }
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe1 $t/a.o -Wl,--no-allow-shlib-undefined -L$t -lfoo -lbar
|
||||
$CC -B. -o $t/exe2 $t/a.o -Wl,--no-allow-shlib-undefined -L$t -lbar
|
||||
|
||||
mv $t/libfoo.so $t/libfoo.so.bak
|
||||
echo | $CC -B. -shared -fPIC -o $t/libfoo.so -xc -
|
||||
|
||||
not $CC -B. -o $t/exe3 $t/a.o -Wl,--no-allow-shlib-undefined -L$t -lfoo -lbar
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
[[ $MACHINE = ppc* ]] && skip
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -c -xc - -fPIC
|
||||
#include <stdio.h>
|
||||
void hello() {
|
||||
printf("Hello world\n");
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC -B. -shared -o $t/b.so $t/a.o
|
||||
|
||||
cat <<EOF | $CC -o $t/c.o -c -xc -
|
||||
#include <stdio.h>
|
||||
void hello();
|
||||
int main() { hello(); }
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe $t/c.o $t/b.so
|
||||
readelf -W --syms $t/exe | not grep -F 'hello$thunk'
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -c -xc - -fPIC
|
||||
#include <stdio.h>
|
||||
void foo1() { printf("foo1\n"); }
|
||||
void foo2() { printf("foo2\n"); }
|
||||
__asm__(".symver foo1, foo@ver1");
|
||||
__asm__(".symver foo2, foo@@ver2");
|
||||
EOF
|
||||
|
||||
echo 'ver1 { local: *; }; ver2 { local: *; };' > $t/b.ver
|
||||
$CC -B. -shared -o $t/libfoo.so $t/a.o -Wl,--version-script=$t/b.ver
|
||||
|
||||
cat <<EOF | $CC -o $t/b.o -c -xc -
|
||||
void foo();
|
||||
int main() { foo(); }
|
||||
__asm__(".symver foo, foo@ver2");
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/exe $t/b.o -L$t -Wl,--as-needed -lfoo -Wl,-rpath=$t
|
||||
$QEMU $t/exe | grep foo2
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
. $(dirname $0)/common.inc
|
||||
|
||||
cat <<EOF | $CC -o $t/a.o -c -xc - -fPIC
|
||||
void foo() {}
|
||||
__asm__(".symver foo, foo@TEST1");
|
||||
__asm__(".symver foo, foo@@TEST2");
|
||||
EOF
|
||||
|
||||
cat <<EOF > $t/b.version
|
||||
TEST1 { local: *; };
|
||||
TEST2 {};
|
||||
TEST3 {};
|
||||
EOF
|
||||
|
||||
$CC -B. -o $t/c.so -shared $t/a.o -Wl,--version-script=$t/b.version
|
||||
|
||||
readelf -W --dyn-syms $t/c.so | grep -F 'foo@TEST1'
|
||||
readelf -W --dyn-syms $t/c.so | grep -F 'foo@@TEST2'
|
||||
@@ -17,5 +17,8 @@ void hello() {
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC -o $t/exe $t/a.o $t/b.o -no-pie
|
||||
$QEMU $t/exe || skip
|
||||
|
||||
$CC -B. -o $t/exe $t/a.o $t/b.o -no-pie
|
||||
$QEMU $t/exe | grep 'Hello world'
|
||||
+1
-1
@@ -17,7 +17,7 @@ int main() {
|
||||
EOF
|
||||
|
||||
$CC -o $t/exe1 $t/a.o -pie
|
||||
$QEMU $t/exe1 | grep 'Hello world' || skip
|
||||
$QEMU $t/exe1 || skip
|
||||
|
||||
$CC -B. -o $t/exe2 $t/a.o -pie
|
||||
$QEMU $t/exe2 | grep 'Hello world'
|
||||
|
||||
+17
-20
@@ -9,42 +9,39 @@
|
||||
# order to be triggered.
|
||||
|
||||
cat <<EOF | $CC -fPIC -c -o $t/a.o -xc -
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// .tdata
|
||||
_Thread_local int x = 42;
|
||||
// .tbss
|
||||
__attribute__ ((aligned(64)))
|
||||
_Thread_local int y = 0;
|
||||
|
||||
void *verify(void *unused) {
|
||||
assert((unsigned long)(&y) % 64 == 0);
|
||||
// .tbss
|
||||
__attribute__((aligned(64))) _Thread_local int y;
|
||||
|
||||
void *test(void *unused) {
|
||||
printf("%p %lu", &y, (unsigned long)&y % 64);
|
||||
return NULL;
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF | $CC -fPIC -c -o $t/b.o -xc -
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <dlfcn.h>
|
||||
#include <assert.h>
|
||||
void *(*verify)(void *);
|
||||
|
||||
int main() {
|
||||
void *handle = dlopen("a.so", RTLD_NOW);
|
||||
assert(handle);
|
||||
*(void**)(&verify) = dlsym(handle, "verify");
|
||||
assert(verify);
|
||||
void *handle = dlopen("c.so", RTLD_NOW);
|
||||
void *(*test)(void *) = dlsym(handle, "test");
|
||||
pthread_t th;
|
||||
|
||||
pthread_t thread;
|
||||
test(NULL);
|
||||
printf(" ");
|
||||
|
||||
verify(NULL);
|
||||
|
||||
pthread_create(&thread, NULL, verify, NULL);
|
||||
pthread_join(thread, NULL);
|
||||
pthread_create(&th, NULL, test, NULL);
|
||||
pthread_join(th, NULL);
|
||||
printf("\n");
|
||||
}
|
||||
EOF
|
||||
|
||||
$CC -B. -shared -o $t/a.so $t/a.o
|
||||
$CC -B. -shared -o $t/c.so $t/a.o
|
||||
$CC -B. -ldl -pthread -o $t/exe $t/b.o -Wl,-rpath,$t
|
||||
$QEMU $t/exe
|
||||
$QEMU $t/exe | grep -E '^0x[0-9a-f]+ 0 0x[0-9a-f]+ 0$'
|
||||
Vendored
+3
-3
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "blake3"
|
||||
version = "1.5.5"
|
||||
version = "1.6.1"
|
||||
authors = ["Jack O'Connor <[email protected]>", "Samuel Neves"]
|
||||
description = "the BLAKE3 hash function"
|
||||
repository = "https://github.com/BLAKE3-team/BLAKE3"
|
||||
@@ -118,8 +118,8 @@ zeroize = { version = "1", default-features = false, optional = true }
|
||||
hmac = "0.12.0"
|
||||
hex = "0.4.2"
|
||||
page_size = "0.6.0"
|
||||
rand = "0.8.0"
|
||||
rand_chacha = "0.3.0"
|
||||
rand = "0.9.0"
|
||||
rand_chacha = "0.9.0"
|
||||
reference_impl = { path = "./reference_impl" }
|
||||
tempfile = "3.8.0"
|
||||
serde_json = "1.0.107"
|
||||
|
||||
+88
-65
@@ -38,24 +38,25 @@ version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.6"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys 0.59.0",
|
||||
"once_cell",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.93"
|
||||
version = "1.0.96"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||
checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
@@ -71,7 +72,7 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "b3sum"
|
||||
version = "1.5.5"
|
||||
version = "1.6.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"blake3",
|
||||
@@ -85,13 +86,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.5.5"
|
||||
version = "1.6.1"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
@@ -104,9 +105,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.1"
|
||||
version = "1.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
|
||||
checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -119,9 +120,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.21"
|
||||
version = "4.5.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f"
|
||||
checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -129,9 +130,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.21"
|
||||
version = "4.5.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec"
|
||||
checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -142,9 +143,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
version = "4.5.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -154,9 +155,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.3"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
@@ -172,9 +173,9 @@ checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.5"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
@@ -191,9 +192,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.20"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "duct"
|
||||
@@ -209,25 +210,37 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
|
||||
checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -249,15 +262,15 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.166"
|
||||
version = "0.2.170"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36"
|
||||
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
version = "0.4.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
@@ -270,9 +283,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
version = "1.20.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
@@ -281,23 +294,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
version = "1.0.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
@@ -314,15 +327,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.41"
|
||||
version = "0.38.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
|
||||
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -332,7 +345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -349,9 +362,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.89"
|
||||
version = "2.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
|
||||
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -360,32 +373,33 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
version = "3.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "terminal_size"
|
||||
version = "0.4.0"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
|
||||
checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9"
|
||||
dependencies = [
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.14"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
checksum = "00e2473a93778eb0bad35909dff6a10d28e63f792f16ed15e404fca9d5eeedbe"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
@@ -393,6 +407,15 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.13.3+wasi-0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wild"
|
||||
version = "2.2.1"
|
||||
@@ -402,15 +425,6 @@ dependencies = [
|
||||
"glob",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
@@ -483,3 +497,12 @@ name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.33.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "b3sum"
|
||||
version = "1.5.5"
|
||||
version = "1.6.1"
|
||||
authors = ["Jack O'Connor <[email protected]>"]
|
||||
description = "a command line implementation of the BLAKE3 hash function"
|
||||
repository = "https://github.com/BLAKE3-team/BLAKE3"
|
||||
@@ -15,7 +15,7 @@ pure = ["blake3/pure"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.25"
|
||||
blake3 = { version = "1", path = "..", features = ["mmap", "rayon"] }
|
||||
blake3 = { version = "1.6.1", path = "..", features = ["mmap", "rayon"] }
|
||||
clap = { version = "4.0.8", features = ["derive", "wrap_help"] }
|
||||
hex = "0.4.0"
|
||||
rayon-core = "1.12.1"
|
||||
|
||||
+18
@@ -419,6 +419,24 @@ fn test_check() {
|
||||
assert_eq!(expected_check_output, stdout);
|
||||
assert_eq!("", stderr);
|
||||
|
||||
// Check the same file, but with Windows-style newlines.
|
||||
let windows_style = expected_checkfile.replace("\n", "\r\n");
|
||||
let output = cmd!(b3sum_exe(), "--check")
|
||||
.stdin_bytes(windows_style.as_bytes())
|
||||
.dir(dir.path())
|
||||
.stdout_capture()
|
||||
.stderr_capture()
|
||||
.run()
|
||||
.unwrap();
|
||||
let stdout = std::str::from_utf8(&output.stdout).unwrap();
|
||||
let stderr = std::str::from_utf8(&output.stderr).unwrap();
|
||||
let expected_check_output = "\
|
||||
a: OK\n\
|
||||
b: OK\n\
|
||||
c/d: OK\n";
|
||||
assert_eq!(expected_check_output, stdout);
|
||||
assert_eq!("", stderr);
|
||||
|
||||
// Now pass the same checkfile twice on the command line just for fun.
|
||||
let checkfile_path = dir.path().join("checkfile");
|
||||
fs::write(&checkfile_path, &expected_checkfile).unwrap();
|
||||
|
||||
Vendored
+1
-1
@@ -27,7 +27,7 @@ impl RandomInput {
|
||||
b.bytes += len as u64;
|
||||
let page_size: usize = page_size::get();
|
||||
let mut buf = vec![0u8; len + page_size];
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = rand::rng();
|
||||
rng.fill_bytes(&mut buf);
|
||||
let mut offsets: Vec<usize> = (0..page_size).collect();
|
||||
offsets.shuffle(&mut rng);
|
||||
|
||||
Vendored
+4
-2
@@ -80,7 +80,8 @@ fn is_big_endian() -> bool {
|
||||
// disabled by old compilers.)
|
||||
fn is_windows_msvc() -> bool {
|
||||
// Some targets are only two components long, so check in steps.
|
||||
target_components()[1] == "pc"
|
||||
let second_component = &target_components()[1];
|
||||
(second_component == "pc" || second_component == "win7")
|
||||
&& target_components()[2] == "windows"
|
||||
&& target_components()[3] == "msvc"
|
||||
}
|
||||
@@ -91,7 +92,8 @@ fn is_windows_msvc() -> bool {
|
||||
// ends with `-gnullvm`.
|
||||
fn is_windows_gnu() -> bool {
|
||||
// Some targets are only two components long, so check in steps.
|
||||
target_components()[1] == "pc"
|
||||
let second_component = &target_components()[1];
|
||||
(second_component == "pc" || second_component == "win7")
|
||||
&& target_components()[2] == "windows"
|
||||
&& target_components()[3] != "msvc"
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -10,7 +10,7 @@ if (POLICY CMP0102)
|
||||
endif()
|
||||
|
||||
project(libblake3
|
||||
VERSION 1.5.5
|
||||
VERSION 1.6.1
|
||||
DESCRIPTION "BLAKE3 C implementation"
|
||||
LANGUAGES C ASM
|
||||
)
|
||||
|
||||
Vendored
+1
-1
@@ -30,7 +30,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BLAKE3_VERSION_STRING "1.5.5"
|
||||
#define BLAKE3_VERSION_STRING "1.6.1"
|
||||
#define BLAKE3_KEY_LEN 32
|
||||
#define BLAKE3_OUT_LEN 32
|
||||
#define BLAKE3_BLOCK_LEN 64
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ neon = []
|
||||
arrayref = "0.3.5"
|
||||
arrayvec = { version = "0.7.0", default-features = false }
|
||||
page_size = "0.6.0"
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.3.1"
|
||||
rand = "0.9.0"
|
||||
rand_chacha = "0.9.0"
|
||||
reference_impl = { path = "../../reference_impl" }
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -29,7 +29,7 @@ impl RandomInput {
|
||||
b.bytes += len as u64;
|
||||
let page_size: usize = page_size::get();
|
||||
let mut buf = vec![0u8; len + page_size];
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = rand::rng();
|
||||
rng.fill_bytes(&mut buf);
|
||||
let mut offsets: Vec<usize> = (0..page_size).collect();
|
||||
offsets.shuffle(&mut rng);
|
||||
|
||||
+1
-1
@@ -584,7 +584,7 @@ fn test_fuzz_hasher() {
|
||||
let mut total_input = 0;
|
||||
// For each test, write 3 inputs of random length.
|
||||
for _ in 0..3 {
|
||||
let input_len = rng.gen_range(0..INPUT_MAX + 1);
|
||||
let input_len = rng.random_range(0..INPUT_MAX + 1);
|
||||
dbg!(input_len);
|
||||
let input = &input_buf[total_input..][..input_len];
|
||||
hasher.update(input);
|
||||
|
||||
+1
@@ -234,6 +234,7 @@ void blake3_xof_many(const uint32_t cv[8],
|
||||
}
|
||||
#if defined(IS_X86)
|
||||
const enum cpu_feature features = get_cpu_features();
|
||||
MAYBE_UNUSED(features);
|
||||
#if !defined(_WIN32) && !defined(BLAKE3_NO_AVX512)
|
||||
if (features & AVX512VL) {
|
||||
blake3_xof_many_avx512(cv, block, block_len, counter, flags, out, outblocks);
|
||||
|
||||
Vendored
+18
-16
@@ -14,22 +14,24 @@ pub unsafe fn hash_many<const N: usize>(
|
||||
flags_end: u8,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_avx2(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
unsafe {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_avx2(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
|
||||
Vendored
+51
-37
@@ -8,7 +8,15 @@ pub unsafe fn compress_in_place(
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
) {
|
||||
ffi::blake3_compress_in_place_avx512(cv.as_mut_ptr(), block.as_ptr(), block_len, counter, flags)
|
||||
unsafe {
|
||||
ffi::blake3_compress_in_place_avx512(
|
||||
cv.as_mut_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting AVX-512.
|
||||
@@ -19,16 +27,18 @@ pub unsafe fn compress_xof(
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
) -> [u8; 64] {
|
||||
let mut out = [0u8; 64];
|
||||
ffi::blake3_compress_xof_avx512(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
);
|
||||
out
|
||||
unsafe {
|
||||
let mut out = [0u8; 64];
|
||||
ffi::blake3_compress_xof_avx512(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting AVX-512.
|
||||
@@ -42,22 +52,24 @@ pub unsafe fn hash_many<const N: usize>(
|
||||
flags_end: u8,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_avx512(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
unsafe {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_avx512(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting AVX-512.
|
||||
@@ -70,16 +82,18 @@ pub unsafe fn xof_many(
|
||||
flags: u8,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
debug_assert_eq!(0, out.len() % BLOCK_LEN, "whole blocks only");
|
||||
ffi::blake3_xof_many_avx512(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
out.len() / BLOCK_LEN,
|
||||
);
|
||||
unsafe {
|
||||
debug_assert_eq!(0, out.len() % BLOCK_LEN, "whole blocks only");
|
||||
ffi::blake3_xof_many_avx512(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
out.len() / BLOCK_LEN,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
|
||||
Vendored
+39
-27
@@ -8,7 +8,15 @@ pub unsafe fn compress_in_place(
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
) {
|
||||
ffi::blake3_compress_in_place_sse2(cv.as_mut_ptr(), block.as_ptr(), block_len, counter, flags)
|
||||
unsafe {
|
||||
ffi::blake3_compress_in_place_sse2(
|
||||
cv.as_mut_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting SSE2.
|
||||
@@ -19,16 +27,18 @@ pub unsafe fn compress_xof(
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
) -> [u8; 64] {
|
||||
let mut out = [0u8; 64];
|
||||
ffi::blake3_compress_xof_sse2(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
);
|
||||
out
|
||||
unsafe {
|
||||
let mut out = [0u8; 64];
|
||||
ffi::blake3_compress_xof_sse2(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting SSE2.
|
||||
@@ -42,22 +52,24 @@ pub unsafe fn hash_many<const N: usize>(
|
||||
flags_end: u8,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_sse2(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
unsafe {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_sse2(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
|
||||
Vendored
+39
-27
@@ -8,7 +8,15 @@ pub unsafe fn compress_in_place(
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
) {
|
||||
ffi::blake3_compress_in_place_sse41(cv.as_mut_ptr(), block.as_ptr(), block_len, counter, flags)
|
||||
unsafe {
|
||||
ffi::blake3_compress_in_place_sse41(
|
||||
cv.as_mut_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting SSE4.1.
|
||||
@@ -19,16 +27,18 @@ pub unsafe fn compress_xof(
|
||||
counter: u64,
|
||||
flags: u8,
|
||||
) -> [u8; 64] {
|
||||
let mut out = [0u8; 64];
|
||||
ffi::blake3_compress_xof_sse41(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
);
|
||||
out
|
||||
unsafe {
|
||||
let mut out = [0u8; 64];
|
||||
ffi::blake3_compress_xof_sse41(
|
||||
cv.as_ptr(),
|
||||
block.as_ptr(),
|
||||
block_len,
|
||||
counter,
|
||||
flags,
|
||||
out.as_mut_ptr(),
|
||||
);
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe because this may only be called on platforms supporting SSE4.1.
|
||||
@@ -42,22 +52,24 @@ pub unsafe fn hash_many<const N: usize>(
|
||||
flags_end: u8,
|
||||
out: &mut [u8],
|
||||
) {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_sse41(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
unsafe {
|
||||
// The Rust hash_many implementations do bounds checking on the `out`
|
||||
// array, but the C implementations don't. Even though this is an unsafe
|
||||
// function, assert the bounds here.
|
||||
assert!(out.len() >= inputs.len() * OUT_LEN);
|
||||
ffi::blake3_hash_many_sse41(
|
||||
inputs.as_ptr() as *const *const u8,
|
||||
inputs.len(),
|
||||
N / BLOCK_LEN,
|
||||
key.as_ptr(),
|
||||
counter,
|
||||
increment_counter.yes(),
|
||||
flags,
|
||||
flags_start,
|
||||
flags_end,
|
||||
out.as_mut_ptr(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ffi {
|
||||
|
||||
Vendored
+3
-18
@@ -50,30 +50,15 @@ pub(crate) fn copy_wide(
|
||||
pub(crate) fn maybe_mmap_file(file: &std::fs::File) -> std::io::Result<Option<memmap2::Mmap>> {
|
||||
let metadata = file.metadata()?;
|
||||
let file_size = metadata.len();
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if !metadata.is_file() {
|
||||
// Not a real file.
|
||||
Ok(None)
|
||||
} else if file_size > isize::max_value() as u64 {
|
||||
// Too long to safely map.
|
||||
// https://github.com/danburkert/memmap-rs/issues/69
|
||||
Ok(None)
|
||||
} else if file_size == 0 {
|
||||
// Mapping an empty file currently fails.
|
||||
// https://github.com/danburkert/memmap-rs/issues/72
|
||||
// See test_mmap_virtual_file.
|
||||
Ok(None)
|
||||
} else if file_size < 16 * 1024 {
|
||||
// Mapping small files is not worth it.
|
||||
// Mapping small files is not worth it, and some special files that can't be mapped report
|
||||
// a size of zero.
|
||||
Ok(None)
|
||||
} else {
|
||||
// Explicitly set the length of the memory map, so that filesystem
|
||||
// changes can't race to violate the invariants we just checked.
|
||||
let map = unsafe {
|
||||
memmap2::MmapOptions::new()
|
||||
.len(file_size as usize)
|
||||
.map(file)?
|
||||
};
|
||||
let map = unsafe { memmap2::Mmap::map(file)? };
|
||||
Ok(Some(map))
|
||||
}
|
||||
}
|
||||
Vendored
+7
@@ -236,6 +236,13 @@ impl Hash {
|
||||
Self(bytes)
|
||||
}
|
||||
|
||||
/// Create a `Hash` from its raw bytes representation as a slice.
|
||||
///
|
||||
/// Returns an error if the slice is not exactly 32 bytes long.
|
||||
pub fn from_slice(bytes: &[u8]) -> Result<Self, core::array::TryFromSliceError> {
|
||||
Ok(Self::from_bytes(bytes.try_into()?))
|
||||
}
|
||||
|
||||
/// Encode a `Hash` in lowercase hexadecimal.
|
||||
///
|
||||
/// The returned [`ArrayString`] is a fixed size and doesn't allocate memory
|
||||
|
||||
Vendored
+14
-4
@@ -544,7 +544,7 @@ fn test_fuzz_hasher() {
|
||||
let mut total_input = 0;
|
||||
// For each test, write 3 inputs of random length.
|
||||
for _ in 0..3 {
|
||||
let input_len = rng.gen_range(0..(INPUT_MAX + 1));
|
||||
let input_len = rng.random_range(0..(INPUT_MAX + 1));
|
||||
#[cfg(feature = "std")]
|
||||
dbg!(input_len);
|
||||
let input = &input_buf[total_input..][..input_len];
|
||||
@@ -573,12 +573,12 @@ fn test_fuzz_xof() {
|
||||
dbg!(_num_test);
|
||||
// 31 (16 + 8 + 4 + 2 + 1) outputs
|
||||
let mut output_buf = [0; 31 * CHUNK_LEN];
|
||||
let input_len = rng.gen_range(0..input_buf.len());
|
||||
let input_len = rng.random_range(0..input_buf.len());
|
||||
let mut xof = crate::Hasher::new()
|
||||
.update(&input_buf[..input_len])
|
||||
.finalize_xof();
|
||||
let partial_start = rng.gen_range(0..output_buf.len());
|
||||
let partial_end = rng.gen_range(partial_start..output_buf.len());
|
||||
let partial_start = rng.random_range(0..output_buf.len());
|
||||
let partial_end = rng.random_range(partial_start..output_buf.len());
|
||||
xof.fill(&mut output_buf[..partial_start]);
|
||||
xof.fill(&mut output_buf[partial_start..partial_end]);
|
||||
xof.fill(&mut output_buf[partial_end..]);
|
||||
@@ -763,6 +763,16 @@ fn test_hash_conversions() {
|
||||
let hex = hash1.to_hex();
|
||||
let hash3 = crate::Hash::from_hex(hex.as_bytes()).unwrap();
|
||||
assert_eq!(hash1, hash3);
|
||||
|
||||
let slice1: &[u8] = bytes1.as_slice();
|
||||
let hash4 = crate::Hash::from_slice(slice1).expect("correct length");
|
||||
assert_eq!(hash1, hash4);
|
||||
|
||||
assert!(crate::Hash::from_slice(&[]).is_err());
|
||||
assert!(crate::Hash::from_slice(&[42]).is_err());
|
||||
assert!(crate::Hash::from_slice([42; 31].as_slice()).is_err());
|
||||
assert!(crate::Hash::from_slice([42; 33].as_slice()).is_err());
|
||||
assert!(crate::Hash::from_slice([42; 100].as_slice()).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Vendored
+1
@@ -3,6 +3,7 @@
|
||||
- Make sure `cargo outdated -R` is clean in the root and in b3sum/.
|
||||
- Bump the version in the root Cargo.toml.
|
||||
- Bump the version in b3sum/Cargo.toml.
|
||||
- Bump the dependency version too, if new features are used.
|
||||
- Delete b3sum/Cargo.lock and recreate it with `cargo build` or similar.
|
||||
- Update the `-h` output in b3sum/README.md if it's changed.
|
||||
- Bump `BLAKE3_VERSION_STRING` in c/blake3.h.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
build
|
||||
ide/vs20??/*.db
|
||||
ide/vs20??/*.opendb
|
||||
ide/vs20??/*.user
|
||||
@@ -8,3 +9,5 @@ docs/
|
||||
*.zip
|
||||
*.tar
|
||||
*.gz
|
||||
.vscode
|
||||
.DS_STore
|
||||
Vendored
+133
-73
@@ -14,7 +14,7 @@ option(MI_TRACK_VALGRIND "Compile with Valgrind support (adds a small overhea
|
||||
option(MI_TRACK_ASAN "Compile with address sanitizer support (adds a small overhead)" OFF)
|
||||
option(MI_TRACK_ETW "Compile with Windows event tracing (ETW) support (adds a small overhead)" OFF)
|
||||
option(MI_USE_CXX "Use the C++ compiler to compile the library (instead of the C compiler)" OFF)
|
||||
option(MI_OPT_ARCH "Only for optimized builds: turn on architecture specific optimizations (for arm64: '-march=armv8.1-a' (2016))" ON)
|
||||
option(MI_OPT_ARCH "Only for optimized builds: turn on architecture specific optimizations (for arm64: '-march=armv8.1-a' (2016))" OFF)
|
||||
option(MI_SEE_ASM "Generate assembly files" OFF)
|
||||
option(MI_OSX_INTERPOSE "Use interpose to override standard malloc on macOS" ON)
|
||||
option(MI_OSX_ZONE "Use malloc zone to override standard malloc on macOS" ON)
|
||||
@@ -35,6 +35,10 @@ option(MI_INSTALL_TOPLEVEL "Install directly into $CMAKE_INSTALL_PREFIX instead
|
||||
option(MI_NO_THP "Disable transparent huge pages support on Linux/Android for the mimalloc process only" OFF)
|
||||
option(MI_EXTRA_CPPDEFS "Extra pre-processor definitions (use as `-DMI_EXTRA_CPPDEFS=\"opt1=val1;opt2=val2\"`)" "")
|
||||
|
||||
# negated options for vcpkg features
|
||||
option(MI_NO_USE_CXX "Use plain C compilation (has priority over MI_USE_CXX)" OFF)
|
||||
option(MI_NO_OPT_ARCH "Do not use architecture specific optimizations (like '-march=armv8.1-a' for example) (has priority over MI_OPT_ARCH)" OFF)
|
||||
|
||||
# deprecated options
|
||||
option(MI_WIN_USE_FLS "Use Fiber local storage on Windows to detect thread termination (deprecated)" OFF)
|
||||
option(MI_CHECK_FULL "Use full internal invariant checking in DEBUG mode (deprecated, use MI_DEBUG_FULL instead)" OFF)
|
||||
@@ -74,6 +78,19 @@ else()
|
||||
set(mi_defines "")
|
||||
endif()
|
||||
|
||||
# pass git revision as a define
|
||||
if(EXISTS "${CMAKE_SOURCE_DIR}/.git/index")
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} "describe" OUTPUT_VARIABLE mi_git_describe RESULT_VARIABLE mi_git_res ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(mi_git_res EQUAL "0")
|
||||
list(APPEND mi_defines "MI_GIT_DESCRIBE=${mi_git_describe}")
|
||||
# add to dependencies so we rebuild if the git head commit changes
|
||||
set_property(GLOBAL APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/.git/index")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Convenience: set default build type and compiler depending on the build directory
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -99,9 +116,44 @@ if("${CMAKE_BINARY_DIR}" MATCHES ".*(S|s)ecure$")
|
||||
set(MI_SECURE "ON")
|
||||
endif()
|
||||
|
||||
|
||||
# Determine architecture
|
||||
set(MI_OPT_ARCH_FLAGS "")
|
||||
set(MI_ARCH "unknown")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|i[3456]86)$" OR CMAKE_GENERATOR_PLATFORM MATCHES "^(x86|Win32)$")
|
||||
set(MI_ARCH "x86")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR "x86_64" IN_LIST CMAKE_OSX_ARCHITECTURES) # must be before arm64
|
||||
set(MI_ARCH "x64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv[89].?|ARM64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64" OR "arm64" IN_LIST CMAKE_OSX_ARCHITECTURES)
|
||||
set(MI_ARCH "arm64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|armv[34567]|ARM)$")
|
||||
set(MI_ARCH "arm32")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|riscv32|riscv64)$")
|
||||
if(CMAKE_SIZEOF_VOID_P==4)
|
||||
set(MI_ARCH "riscv32")
|
||||
else()
|
||||
set(MI_ARCH "riscv64")
|
||||
endif()
|
||||
else()
|
||||
set(MI_ARCH ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
message(STATUS "Architecture: ${MI_ARCH}") # (${CMAKE_SYSTEM_PROCESSOR}, ${CMAKE_GENERATOR_PLATFORM}, ${CMAKE_GENERATOR})")
|
||||
|
||||
# negative overrides (mainly to support vcpkg features)
|
||||
if(MI_NO_USE_CXX)
|
||||
set(MI_USE_CXX "OFF")
|
||||
endif()
|
||||
if(MI_NO_OPT_ARCH)
|
||||
set(MI_OPT_ARCH "OFF")
|
||||
elseif(MI_ARCH STREQUAL "arm64")
|
||||
set(MI_OPT_ARCH "ON") # enable armv8.1-a by default on arm64 unless MI_NO_OPT_ARCH is set
|
||||
endif()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Process options
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
set(MI_CLANG_CL "ON")
|
||||
endif()
|
||||
@@ -125,14 +177,6 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC|Intel")
|
||||
set(MI_USE_CXX "ON")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Release|RelWithDebInfo")
|
||||
if (NOT MI_OPT_ARCH)
|
||||
message(STATUS "Architecture specific optimizations are disabled (MI_OPT_ARCH=OFF)")
|
||||
endif()
|
||||
else()
|
||||
set(MI_OPT_ARCH OFF)
|
||||
endif()
|
||||
|
||||
if(MI_OVERRIDE)
|
||||
message(STATUS "Override standard malloc (MI_OVERRIDE=ON)")
|
||||
if(APPLE)
|
||||
@@ -339,28 +383,6 @@ if(MI_WIN_USE_FIXED_TLS)
|
||||
list(APPEND mi_defines MI_WIN_USE_FIXED_TLS=1)
|
||||
endif()
|
||||
|
||||
# Determine architecture
|
||||
set(MI_OPT_ARCH_FLAGS "")
|
||||
set(MI_ARCH "unknown")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86|i[3456]86)$" OR CMAKE_GENERATOR_PLATFORM MATCHES "^(x86|Win32)$")
|
||||
set(MI_ARCH "x86")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(x86_64|x64|amd64|AMD64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "x64") # must be before arm64
|
||||
set(MI_ARCH "x64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(aarch64|arm64|armv8.?|ARM64)$" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64")
|
||||
set(MI_ARCH "arm64")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|armv[34567]|ARM)$")
|
||||
set(MI_ARCH "arm32")
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|riscv32|riscv64)$")
|
||||
if(CMAKE_SIZEOF_VOID_P==4)
|
||||
set(MI_ARCH "riscv32")
|
||||
else()
|
||||
set(MI_ARCH "riscv64")
|
||||
endif()
|
||||
else()
|
||||
set(MI_ARCH ${CMAKE_SYSTEM_PROCESSOR})
|
||||
endif()
|
||||
message(STATUS "Architecture: ${MI_ARCH}") # (${CMAKE_SYSTEM_PROCESSOR}, ${CMAKE_GENERATOR_PLATFORM}, ${CMAKE_GENERATOR})")
|
||||
|
||||
# Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits.
|
||||
# (this will skip the aligned hinting in that case. Issue #939, #949)
|
||||
if (EXISTS /proc/cpuinfo)
|
||||
@@ -385,7 +407,7 @@ if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU" AND NOT MI_CLANG_CL)
|
||||
endif()
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang")
|
||||
list(APPEND mi_cflags -Wno-static-in-inline)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "Intel")
|
||||
@@ -412,8 +434,12 @@ endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID MATCHES "AppleClang|Clang|GNU|Intel" AND NOT CMAKE_SYSTEM_NAME MATCHES "Haiku")
|
||||
if(MI_OPT_ARCH)
|
||||
if(MI_ARCH STREQUAL "arm64")
|
||||
set(MI_OPT_ARCH_FLAGS "-march=armv8.1-a") # fast atomics
|
||||
if(APPLE AND CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_OSX_ARCHITECTURES) # to support multi-arch binaries (#999)
|
||||
if("arm64" IN_LIST CMAKE_OSX_ARCHITECTURES)
|
||||
list(APPEND MI_OPT_ARCH_FLAGS "-Xarch_arm64;-march=armv8.1-a")
|
||||
endif()
|
||||
elseif(MI_ARCH STREQUAL "arm64")
|
||||
set(MI_OPT_ARCH_FLAGS "-march=armv8.1-a") # fast atomics
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -422,13 +448,13 @@ if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914)
|
||||
list(APPEND mi_cflags /Zc:__cplusplus)
|
||||
if(MI_OPT_ARCH AND NOT MI_CLANG_CL)
|
||||
if(MI_ARCH STREQUAL "arm64")
|
||||
set(MI_OPT_ARCH_FLAGS "/arch:armv8.1") # fast atomics
|
||||
set(MI_OPT_ARCH_FLAGS "/arch:armv8.1") # fast atomics
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(MINGW)
|
||||
add_definitions(-D_WIN32_WINNT=0x601) # issue #976
|
||||
add_definitions(-D_WIN32_WINNT=0x600) # issue #976
|
||||
endif()
|
||||
|
||||
if(MI_OPT_ARCH_FLAGS)
|
||||
@@ -474,13 +500,13 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Install and output names
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# dynamic/shared library and symlinks always go to /usr/local/lib equivalent
|
||||
set(mi_install_libdir "${CMAKE_INSTALL_LIBDIR}")
|
||||
set(mi_install_bindir "${CMAKE_INSTALL_BINDIR}")
|
||||
# we use ${CMAKE_INSTALL_BINDIR} and ${CMAKE_INSTALL_LIBDIR}.
|
||||
|
||||
# static libraries and object files, includes, and cmake config files
|
||||
# are either installed at top level, or use versioned directories for side-by-side installation (default)
|
||||
@@ -494,19 +520,20 @@ else()
|
||||
set(mi_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/mimalloc-${mi_version}") # for cmake package info
|
||||
endif()
|
||||
|
||||
set(mi_basename "mimalloc")
|
||||
set(mi_libname "mimalloc")
|
||||
if(MI_SECURE)
|
||||
set(mi_basename "${mi_basename}-secure")
|
||||
set(mi_libname "${mi_libname}-secure")
|
||||
endif()
|
||||
if(MI_TRACK_VALGRIND)
|
||||
set(mi_basename "${mi_basename}-valgrind")
|
||||
set(mi_libname "${mi_libname}-valgrind")
|
||||
endif()
|
||||
if(MI_TRACK_ASAN)
|
||||
set(mi_basename "${mi_basename}-asan")
|
||||
set(mi_libname "${mi_libname}-asan")
|
||||
endif()
|
||||
string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LC)
|
||||
list(APPEND mi_defines "MI_CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE_LC}") #todo: multi-config project needs $<CONFIG> ?
|
||||
if(NOT(CMAKE_BUILD_TYPE_LC MATCHES "^(release|relwithdebinfo|minsizerel|none)$"))
|
||||
set(mi_basename "${mi_basename}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version
|
||||
set(mi_libname "${mi_libname}-${CMAKE_BUILD_TYPE_LC}") #append build type (e.g. -debug) if not a release version
|
||||
endif()
|
||||
|
||||
if(MI_BUILD_SHARED)
|
||||
@@ -523,7 +550,7 @@ if(MI_BUILD_TESTS)
|
||||
endif()
|
||||
|
||||
message(STATUS "")
|
||||
message(STATUS "Library base name: ${mi_basename}")
|
||||
message(STATUS "Library name : ${mi_libname}")
|
||||
message(STATUS "Version : ${mi_version}.${mi_version_patch}")
|
||||
message(STATUS "Build type : ${CMAKE_BUILD_TYPE_LC}")
|
||||
if(MI_USE_CXX)
|
||||
@@ -544,7 +571,7 @@ message(STATUS "")
|
||||
# shared library
|
||||
if(MI_BUILD_SHARED)
|
||||
add_library(mimalloc SHARED ${mi_sources})
|
||||
set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} SOVERSION ${mi_version_major} OUTPUT_NAME ${mi_basename} )
|
||||
set_target_properties(mimalloc PROPERTIES VERSION ${mi_version} SOVERSION ${mi_version_major} OUTPUT_NAME ${mi_libname} )
|
||||
target_compile_definitions(mimalloc PRIVATE ${mi_defines} MI_SHARED_LIB MI_SHARED_LIB_EXPORT)
|
||||
target_compile_options(mimalloc PRIVATE ${mi_cflags} ${mi_cflags_dynamic})
|
||||
target_link_libraries(mimalloc PRIVATE ${mi_libraries})
|
||||
@@ -552,6 +579,18 @@ if(MI_BUILD_SHARED)
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${mi_install_incdir}>
|
||||
)
|
||||
install(TARGETS mimalloc EXPORT mimalloc ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir})
|
||||
|
||||
if(WIN32)
|
||||
# On windows, the import library name for the dll would clash with the static mimalloc.lib library
|
||||
# so we postfix the dll import library with `.dll.lib` (and also the .pdb debug file)
|
||||
set_property(TARGET mimalloc PROPERTY ARCHIVE_OUTPUT_NAME "${mi_libname}.dll" )
|
||||
install(FILES "$<TARGET_FILE_DIR:mimalloc>/${mi_libname}.dll.lib" DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
set_property(TARGET mimalloc PROPERTY PDB_NAME "${mi_libname}.dll")
|
||||
# don't try to install the pdb since it may not be generated depending on the configuration
|
||||
# install(FILES "$<TARGET_FILE_DIR:mimalloc>/${mi_libname}.dll.pdb" DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
if(WIN32 AND MI_WIN_REDIRECT)
|
||||
# On windows, link and copy the mimalloc redirection dll too.
|
||||
if(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64ec")
|
||||
@@ -559,8 +598,8 @@ if(MI_BUILD_SHARED)
|
||||
elseif(MI_ARCH STREQUAL "x64")
|
||||
set(MIMALLOC_REDIRECT_SUFFIX "")
|
||||
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
|
||||
message(STATUS "Note: x64 code emulated on Windows for arm64 should use an arm64ec build of 'mimalloc-override.dll'")
|
||||
message(STATUS " with 'mimalloc-redirect-arm64ec.dll'. See the 'bin\\readme.md' for more information.")
|
||||
message(STATUS "Note: x64 code emulated on Windows for arm64 should use an arm64ec build of 'mimalloc.dll'")
|
||||
message(STATUS " together with 'mimalloc-redirect-arm64ec.dll'. See the 'bin\\readme.md' for more information.")
|
||||
endif()
|
||||
elseif(MI_ARCH STREQUAL "x86")
|
||||
set(MIMALLOC_REDIRECT_SUFFIX "32")
|
||||
@@ -568,20 +607,19 @@ if(MI_BUILD_SHARED)
|
||||
set(MIMALLOC_REDIRECT_SUFFIX "-${MI_ARCH}") # -arm64 etc.
|
||||
endif()
|
||||
|
||||
target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.lib)
|
||||
target_link_libraries(mimalloc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.lib) # the DLL import library
|
||||
add_custom_command(TARGET mimalloc POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/bin/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" $<TARGET_FILE_DIR:mimalloc>
|
||||
COMMENT "Copy mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll to output directory")
|
||||
install(FILES "$<TARGET_FILE_DIR:mimalloc>/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" DESTINATION ${mi_install_bindir})
|
||||
install(FILES "$<TARGET_FILE_DIR:mimalloc>/mimalloc-redirect${MIMALLOC_REDIRECT_SUFFIX}.dll" DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
install(TARGETS mimalloc EXPORT mimalloc ARCHIVE DESTINATION ${mi_install_libdir} RUNTIME DESTINATION ${mi_install_bindir} LIBRARY DESTINATION ${mi_install_libdir})
|
||||
install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir})
|
||||
endif()
|
||||
|
||||
|
||||
# static library
|
||||
if (MI_BUILD_STATIC)
|
||||
add_library(mimalloc-static STATIC ${mi_sources})
|
||||
set_property(TARGET mimalloc-static PROPERTY OUTPUT_NAME ${mi_libname})
|
||||
set_property(TARGET mimalloc-static PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
target_compile_definitions(mimalloc-static PRIVATE ${mi_defines} MI_STATIC_LIB)
|
||||
target_compile_options(mimalloc-static PRIVATE ${mi_cflags} ${mi_cflags_static})
|
||||
@@ -590,15 +628,6 @@ if (MI_BUILD_STATIC)
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${mi_install_incdir}>
|
||||
)
|
||||
if(WIN32)
|
||||
# When building both static and shared libraries on Windows, a static library should use a
|
||||
# different output name to avoid the conflict with the import library of a shared one.
|
||||
string(REPLACE "mimalloc" "mimalloc-static" mi_output_name ${mi_basename})
|
||||
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_output_name})
|
||||
else()
|
||||
set_target_properties(mimalloc-static PROPERTIES OUTPUT_NAME ${mi_basename})
|
||||
endif()
|
||||
|
||||
install(TARGETS mimalloc-static EXPORT mimalloc DESTINATION ${mi_install_objdir} LIBRARY)
|
||||
install(EXPORT mimalloc DESTINATION ${mi_install_cmakedir})
|
||||
endif()
|
||||
@@ -607,6 +636,7 @@ endif()
|
||||
install(FILES include/mimalloc.h DESTINATION ${mi_install_incdir})
|
||||
install(FILES include/mimalloc-override.h DESTINATION ${mi_install_incdir})
|
||||
install(FILES include/mimalloc-new-delete.h DESTINATION ${mi_install_incdir})
|
||||
install(FILES include/mimalloc-stats.h DESTINATION ${mi_install_incdir})
|
||||
install(FILES cmake/mimalloc-config.cmake DESTINATION ${mi_install_cmakedir})
|
||||
install(FILES cmake/mimalloc-config-version.cmake DESTINATION ${mi_install_cmakedir})
|
||||
|
||||
@@ -623,12 +653,15 @@ if (MI_BUILD_OBJECT)
|
||||
)
|
||||
|
||||
# Copy the generated object file (`static.o`) to the output directory (as `mimalloc.o`)
|
||||
if(NOT WIN32)
|
||||
if(CMAKE_GENERATOR MATCHES "^Visual Studio.*$")
|
||||
set(mimalloc-obj-static "${CMAKE_CURRENT_BINARY_DIR}/mimalloc-obj.dir/$<CONFIG>/static${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
else()
|
||||
set(mimalloc-obj-static "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/mimalloc-obj.dir/src/static.c${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
set(mimalloc-obj-out "${CMAKE_CURRENT_BINARY_DIR}/${mi_basename}${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
add_custom_command(OUTPUT ${mimalloc-obj-out} DEPENDS mimalloc-obj COMMAND "${CMAKE_COMMAND}" -E copy "${mimalloc-obj-static}" "${mimalloc-obj-out}")
|
||||
add_custom_target(mimalloc-obj-target ALL DEPENDS ${mimalloc-obj-out})
|
||||
endif()
|
||||
set(mimalloc-obj-out "${CMAKE_CURRENT_BINARY_DIR}/${mi_libname}${CMAKE_C_OUTPUT_EXTENSION}")
|
||||
add_custom_command(OUTPUT ${mimalloc-obj-out} DEPENDS mimalloc-obj COMMAND "${CMAKE_COMMAND}" -E copy "${mimalloc-obj-static}" "${mimalloc-obj-out}")
|
||||
add_custom_target(mimalloc-obj-target ALL DEPENDS ${mimalloc-obj-out})
|
||||
|
||||
|
||||
# the following seems to lead to cmake warnings/errors on some systems, disable for now :-(
|
||||
# install(TARGETS mimalloc-obj EXPORT mimalloc DESTINATION ${mi_install_objdir})
|
||||
@@ -637,22 +670,23 @@ if (MI_BUILD_OBJECT)
|
||||
# but that fails cmake versions less than 3.10 so we leave it as is for now
|
||||
install(FILES ${mimalloc-obj-static}
|
||||
DESTINATION ${mi_install_objdir}
|
||||
RENAME ${mi_basename}${CMAKE_C_OUTPUT_EXTENSION} )
|
||||
RENAME ${mi_libname}${CMAKE_C_OUTPUT_EXTENSION} )
|
||||
endif()
|
||||
|
||||
|
||||
# pkg-config file support
|
||||
set(pc_libraries "")
|
||||
set(mi_pc_libraries "")
|
||||
foreach(item IN LISTS mi_libraries)
|
||||
if(item MATCHES " *[-].*")
|
||||
set(pc_libraries "${pc_libraries} ${item}")
|
||||
set(mi_pc_libraries "${mi_pc_libraries} ${item}")
|
||||
else()
|
||||
set(pc_libraries "${pc_libraries} -l${item}")
|
||||
set(mi_pc_libraries "${mi_pc_libraries} -l${item}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include("cmake/JoinPaths.cmake")
|
||||
join_paths(includedir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
join_paths(libdir_for_pc_file "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||
join_paths(mi_pc_includedir "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
|
||||
join_paths(mi_pc_libdir "\${prefix}" "${CMAKE_INSTALL_LIBDIR}")
|
||||
|
||||
configure_file(mimalloc.pc.in mimalloc.pc @ONLY)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mimalloc.pc"
|
||||
@@ -667,15 +701,41 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mimalloc.pc"
|
||||
if (MI_BUILD_TESTS)
|
||||
enable_testing()
|
||||
|
||||
# static link tests
|
||||
foreach(TEST_NAME api api-fill stress)
|
||||
add_executable(mimalloc-test-${TEST_NAME} test/test-${TEST_NAME}.c)
|
||||
target_compile_definitions(mimalloc-test-${TEST_NAME} PRIVATE ${mi_defines})
|
||||
target_compile_options(mimalloc-test-${TEST_NAME} PRIVATE ${mi_cflags})
|
||||
target_include_directories(mimalloc-test-${TEST_NAME} PRIVATE include)
|
||||
target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc ${mi_libraries})
|
||||
|
||||
if(MI_BUILD_SHARED AND (MI_TRACK_ASAN OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
|
||||
target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc ${mi_libraries})
|
||||
else()
|
||||
target_link_libraries(mimalloc-test-${TEST_NAME} PRIVATE mimalloc-static ${mi_libraries})
|
||||
endif()
|
||||
add_test(NAME test-${TEST_NAME} COMMAND mimalloc-test-${TEST_NAME})
|
||||
endforeach()
|
||||
|
||||
# dynamic override test
|
||||
if(MI_BUILD_SHARED AND NOT (MI_TRACK_ASAN OR MI_DEBUG_TSAN OR MI_DEBUG_UBSAN))
|
||||
add_executable(mimalloc-test-stress-dynamic test/test-stress.c)
|
||||
target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE ${mi_defines} "USE_STD_MALLOC=1")
|
||||
if(WIN32)
|
||||
target_compile_definitions(mimalloc-test-stress-dynamic PRIVATE "MI_LINK_VERSION=1")
|
||||
endif()
|
||||
target_compile_options(mimalloc-test-stress-dynamic PRIVATE ${mi_cflags})
|
||||
target_include_directories(mimalloc-test-stress-dynamic PRIVATE include)
|
||||
target_link_libraries(mimalloc-test-stress-dynamic PRIVATE mimalloc ${mi_libraries}) # mi_version
|
||||
if(WIN32)
|
||||
add_test(NAME test-stress-dynamic COMMAND ${CMAKE_COMMAND} -E env MIMALLOC_SHOW_STATS=1 $<TARGET_FILE:mimalloc-test-stress-dynamic>)
|
||||
else()
|
||||
if(APPLE)
|
||||
set(LD_PRELOAD "DYLD_INSERT_LIBRARIES")
|
||||
else()
|
||||
set(LD_PRELOAD "LD_PRELOAD")
|
||||
endif()
|
||||
add_test(NAME test-stress-dynamic COMMAND ${CMAKE_COMMAND} -E env MIMALLOC_SHOW_STATS=1 ${LD_PRELOAD}=$<TARGET_FILE:mimalloc> $<TARGET_FILE:mimalloc-test-stress-dynamic>)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
-43
@@ -241,49 +241,6 @@ jobs:
|
||||
workingDirectory: $(BuildType)
|
||||
displayName: CTest
|
||||
|
||||
- job:
|
||||
displayName: Ubuntu 20.04
|
||||
pool:
|
||||
vmImage:
|
||||
ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
Debug:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BuildType: debug
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON
|
||||
Debug++:
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
BuildType: debug-cxx
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON
|
||||
Debug Clang:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
BuildType: debug-clang
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON
|
||||
Debug++ Clang:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
BuildType: debug-clang-cxx
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Debug -DMI_DEBUG_FULL=ON -DMI_USE_CXX=ON
|
||||
Release Clang:
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
BuildType: release-clang
|
||||
cmakeExtraArgs: -DCMAKE_BUILD_TYPE=Release
|
||||
steps:
|
||||
- task: CMake@1
|
||||
inputs:
|
||||
workingDirectory: $(BuildType)
|
||||
cmakeArgs: .. $(cmakeExtraArgs)
|
||||
- script: make -j$(nproc) -C $(BuildType)
|
||||
displayName: Make
|
||||
- script: ctest --verbose --timeout 240
|
||||
workingDirectory: $(BuildType)
|
||||
displayName: CTest
|
||||
|
||||
- job:
|
||||
displayName: macOS 15 (Sequoia)
|
||||
pool:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
BIN
Binary file not shown.
Vendored
+22
-6
@@ -1,15 +1,14 @@
|
||||
# Windows Override
|
||||
|
||||
<span id="override_on_windows">Dynamically overriding on mimalloc on Windows</span>
|
||||
is robust and has the particular advantage to be able to redirect all malloc/free calls
|
||||
that go through the (dynamic) C runtime allocator, including those from other DLL's or
|
||||
libraries. As it intercepts all allocation calls on a low level, it can be used reliably
|
||||
on large programs that include other 3rd party components.
|
||||
<span id="override_on_windows">We use a separate redirection DLL to override mimalloc on Windows</span>
|
||||
such that we redirect all malloc/free calls that go through the (dynamic) C runtime allocator,
|
||||
including those from other DLL's or libraries. As it intercepts all allocation calls on a low level,
|
||||
it can be used on large programs that include other 3rd party components.
|
||||
There are four requirements to make the overriding work well:
|
||||
|
||||
1. Use the C-runtime library as a DLL (using the `/MD` or `/MDd` switch).
|
||||
|
||||
2. Link your program explicitly with the `mimalloc.lib` export library for
|
||||
2. Link your program explicitly with the `mimalloc.dll.lib` export library for
|
||||
the `mimalloc.dll` -- which contains all mimalloc functionality.
|
||||
To ensure the `mimalloc.dll` is actually loaded at run-time it is easiest
|
||||
to insert some call to the mimalloc API in the `main` function, like `mi_version()`
|
||||
@@ -26,6 +25,23 @@ There are four requirements to make the overriding work well:
|
||||
list of the final executable (so it can intercept all potential allocations).
|
||||
You can use `minject -l <exe>` to check this if needed.
|
||||
|
||||
```csharp
|
||||
┌──────────────┐
|
||||
│ Your Program │
|
||||
└────┬─────────┘
|
||||
│
|
||||
│ mi_version() ┌───────────────┐ ┌───────────────────────┐
|
||||
├──────────────►│ mimalloc.dll ├────►│ mimalloc-redirect.dll │
|
||||
│ └──────┬────────┘ └───────────────────────┘
|
||||
│ ▼
|
||||
│ malloc() etc. ┌──────────────┐
|
||||
├──────────────►│ ucrtbase.dll │
|
||||
│ └──────────────┘
|
||||
│
|
||||
│
|
||||
└──────────────► ...
|
||||
```
|
||||
|
||||
For best performance on Windows with C++, it
|
||||
is also recommended to also override the `new`/`delete` operations (by including
|
||||
[`mimalloc-new-delete.h`](../include/mimalloc-new-delete.h)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
set(mi_version_major 2)
|
||||
set(mi_version_minor 1)
|
||||
set(mi_version_patch 9)
|
||||
set(mi_version_minor 2)
|
||||
set(mi_version_patch 2)
|
||||
set(mi_version ${mi_version_major}.${mi_version_minor})
|
||||
|
||||
set(PACKAGE_VERSION ${mi_version})
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,63 @@
|
||||
vcpkg_from_github(
|
||||
OUT_SOURCE_PATH SOURCE_PATH
|
||||
REPO microsoft/mimalloc
|
||||
HEAD_REF master
|
||||
|
||||
# The "REF" can be a commit hash, branch name (dev2), or a version (v2.2.1).
|
||||
# REF "v${VERSION}"
|
||||
REF e2db21e9ba9fb9172b7b0aa0fe9b8742525e8774
|
||||
|
||||
# The sha512 is the hash of the tar.gz bundle.
|
||||
# (To get the sha512, run `vcpkg install mimalloc[override] --overlay-ports=<dir of this file>` and copy the sha from the error message.)
|
||||
SHA512 8cbb601fdf8b46dd6a9c0d314d6da9d4960699853829e96d2470753867f90689fb4caeaf30d628943fd388670dc11902dbecc9cc7c329b99a510524a09bdb612
|
||||
)
|
||||
|
||||
vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
|
||||
FEATURES
|
||||
c MI_NO_USE_CXX
|
||||
guarded MI_GUARDED
|
||||
secure MI_SECURE
|
||||
override MI_OVERRIDE
|
||||
optarch MI_OPT_ARCH
|
||||
optsimd MI_OPT_SIMD
|
||||
xmalloc MI_XMALLOC
|
||||
asm MI_SEE_ASM
|
||||
)
|
||||
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "static" MI_BUILD_STATIC)
|
||||
string(COMPARE EQUAL "${VCPKG_LIBRARY_LINKAGE}" "dynamic" MI_BUILD_SHARED)
|
||||
|
||||
vcpkg_cmake_configure(
|
||||
SOURCE_PATH "${SOURCE_PATH}"
|
||||
OPTIONS
|
||||
-DMI_USE_CXX=ON
|
||||
-DMI_BUILD_TESTS=OFF
|
||||
-DMI_BUILD_OBJECT=ON
|
||||
-DMI_BUILD_STATIC=${MI_BUILD_STATIC}
|
||||
-DMI_BUILD_SHARED=${MI_BUILD_SHARED}
|
||||
-DMI_INSTALL_TOPLEVEL=ON
|
||||
${FEATURE_OPTIONS}
|
||||
)
|
||||
|
||||
vcpkg_cmake_install()
|
||||
vcpkg_copy_pdbs()
|
||||
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_LIST_DIR}/vcpkg-cmake-wrapper.cmake"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/usage"
|
||||
DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}"
|
||||
)
|
||||
vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/mimalloc)
|
||||
|
||||
if(VCPKG_LIBRARY_LINKAGE STREQUAL "dynamic")
|
||||
# todo: why is this needed?
|
||||
vcpkg_replace_string(
|
||||
"${CURRENT_PACKAGES_DIR}/include/mimalloc.h"
|
||||
"!defined(MI_SHARED_LIB)"
|
||||
"0 // !defined(MI_SHARED_LIB)"
|
||||
)
|
||||
endif()
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")
|
||||
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share")
|
||||
|
||||
vcpkg_fixup_pkgconfig()
|
||||
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# Vcpkg support
|
||||
|
||||
This directory is meant to provide the sources for the official [vcpkg port]
|
||||
of mimalloc, but can also be used to override the official port with
|
||||
your own variant.
|
||||
|
||||
For example, you can edit the [`portfile.cmake`](portfile.cmake)
|
||||
to check out a specific commit, version, or branch of mimalloc, or set further options.
|
||||
You can install such custom port as:
|
||||
|
||||
```sh
|
||||
$ vcpkg install "mimalloc[override]" --recurse --overlay-ports=./contrib/vcpkg
|
||||
```
|
||||
|
||||
This will also show the correct sha512 hash if you use a custom version.
|
||||
Another way is to refer to the overlay from the [vcpkg-configuration.json](https://learn.microsoft.com/en-us/vcpkg/reference/vcpkg-configuration-json) file.
|
||||
See also the vcpkg [documentation](https://learn.microsoft.com/en-us/vcpkg/produce/update-package-version) for more information.
|
||||
|
||||
|
||||
# Using mimalloc from vcpkg
|
||||
|
||||
When using [cmake with vcpkg](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started?pivots=shell-powershell),
|
||||
you can use mimalloc from the `CMakeLists.txt` as:
|
||||
|
||||
```cmake
|
||||
find_package(mimalloc CONFIG REQUIRED)
|
||||
target_link_libraries(main PRIVATE mimalloc)
|
||||
```
|
||||
|
||||
See [`test/CMakeLists.txt](../../test/CMakeLists.txt) for more examples.
|
||||
|
||||
|
||||
# Acknowledgements
|
||||
|
||||
The original port for vckpg was contributed by many people, including: @vicroms, @myd7349, @PhoubeHui, @LilyWangL,
|
||||
@JonLiu1993, @RT2Code, Remy Tassoux, @wangao, @BillyONeal, @jiayuehua, @dg0yt, @gerar-ryan-immersaview, @nickdademo,
|
||||
and @jimwang118 -- Thank you so much!
|
||||
|
||||
|
||||
[vcpkg port]: https://github.com/microsoft/vcpkg/tree/master/ports/mimalloc
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Use the following CMake targets to import mimalloc:
|
||||
|
||||
find_package(mimalloc CONFIG REQUIRED)
|
||||
target_link_libraries(main PRIVATE mimalloc)
|
||||
|
||||
And use mimalloc in your sources as:
|
||||
|
||||
#include <mimalloc.h>
|
||||
#include <stdio.h>
|
||||
int main(int argc, char** argv) {
|
||||
int* p = mi_malloc_tp(int);
|
||||
*p = mi_version();
|
||||
printf("mimalloc version: %d\n", *p);
|
||||
mi_free(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
When dynamically overriding on Windows, ensure `mimalloc.dll` is linked through some call to
|
||||
mimalloc (e.g. `mi_version()`), and that the `mimalloc-redirect.dll` is in the same directory.
|
||||
See https://github.com/microsoft/mimalloc/blob/dev/bin/readme.md for detailed information.
|
||||
@@ -0,0 +1,20 @@
|
||||
_find_package(${ARGS})
|
||||
|
||||
if(CMAKE_CURRENT_LIST_DIR STREQUAL "${MIMALLOC_CMAKE_DIR}/${MIMALLOC_VERSION_DIR}")
|
||||
set(MIMALLOC_INCLUDE_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
|
||||
# As in vcpkg.cmake
|
||||
if(NOT DEFINED CMAKE_BUILD_TYPE OR CMAKE_BUILD_TYPE MATCHES "^[Dd][Ee][Bb][Uu][Gg]$")
|
||||
set(MIMALLOC_LIBRARY_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/debug/lib")
|
||||
else()
|
||||
set(MIMALLOC_LIBRARY_DIR "${VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/lib")
|
||||
endif()
|
||||
set(MIMALLOC_OBJECT_DIR "${MIMALLOC_LIBRARY_DIR}")
|
||||
set(MIMALLOC_TARGET_DIR "${MIMALLOC_LIBRARY_DIR}")
|
||||
endif()
|
||||
|
||||
# vcpkg always configures either a static or dynamic library.
|
||||
# ensure to always expose the mimalloc target as either the static or dynamic build.
|
||||
if(TARGET mimalloc-static AND NOT TARGET mimalloc)
|
||||
add_library(mimalloc INTERFACE IMPORTED)
|
||||
set_target_properties(mimalloc PROPERTIES INTERFACE_LINK_LIBRARIES mimalloc-static)
|
||||
endif()
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "mimalloc",
|
||||
"version": "2.2.2",
|
||||
"port-version": 1,
|
||||
"description": "Compact general purpose allocator with excellent performance",
|
||||
"homepage": "https://github.com/microsoft/mimalloc",
|
||||
"license": "MIT",
|
||||
"supports": "!uwp",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "vcpkg-cmake",
|
||||
"host": true
|
||||
},
|
||||
{
|
||||
"name": "vcpkg-cmake-config",
|
||||
"host": true
|
||||
}
|
||||
],
|
||||
"features": {
|
||||
"c": {
|
||||
"description": "Use C11 compilation (this can still override new/delete)"
|
||||
},
|
||||
"override": {
|
||||
"description": "Override the standard malloc/free interface"
|
||||
},
|
||||
"secure": {
|
||||
"description": "Use full security mitigations (like guard pages and randomization)"
|
||||
},
|
||||
"guarded": {
|
||||
"description": "Use build that support guard pages after objects controlled with MIMALLOC_GUARDED_SAMPLE_RATE"
|
||||
},
|
||||
"xmalloc": {
|
||||
"description": "If out-of-memory, call abort() instead of returning NULL"
|
||||
},
|
||||
"optarch": {
|
||||
"description": "Use architecture specific optimizations (on x64: '-march=haswell;-mavx2', on arm64: '-march=armv8.1-a')"
|
||||
},
|
||||
"optsimd": {
|
||||
"description": "Allow use of SIMD instructions (avx2 or neon) (requires 'optarch' to be enabled)"
|
||||
},
|
||||
"asm": {
|
||||
"description": "Generate assembly files"
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
-14
@@ -120,49 +120,52 @@
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">
|
||||
<OutDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
<TargetExt>.lib</TargetExt>
|
||||
<TargetName>mimalloc-static</TargetName>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnabled>false</VcpkgEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@@ -305,7 +308,7 @@
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
|
||||
<CompileAs>CompileAsCpp</CompileAs>
|
||||
<CompileAs>CompileAsC</CompileAs>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
</ClCompile>
|
||||
@@ -422,12 +425,14 @@
|
||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||
<ClCompile Include="..\..\src\alloc.c" />
|
||||
<ClCompile Include="..\..\src\arena-abandon.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena.c" />
|
||||
<ClCompile Include="..\..\src\bitmap.c">
|
||||
@@ -481,6 +486,7 @@
|
||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc.h" />
|
||||
<ClInclude Include="$(ProjectDir)..\..\include\mimalloc-override.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc-stats.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc\atomic.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc\internal.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc\prim.h" />
|
||||
@@ -491,4 +497,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -16,9 +16,6 @@
|
||||
<ClCompile Include="..\..\src\arena.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena-abandoned.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\bitmap.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
@@ -64,6 +61,9 @@
|
||||
<ClCompile Include="..\..\src\stats.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena-abandon.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\mimalloc\atomic.h">
|
||||
@@ -93,6 +93,9 @@
|
||||
<ClInclude Include="..\..\include\mimalloc\prim.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\mimalloc-stats.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Headers">
|
||||
|
||||
@@ -160,6 +160,9 @@
|
||||
<TargetExt>.dll</TargetExt>
|
||||
<TargetName>mimalloc</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnabled>false</VcpkgEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
@@ -180,6 +183,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)"</Command>
|
||||
@@ -208,6 +213,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)"</Command>
|
||||
@@ -236,6 +243,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64.dll" "$(OutputPath)"</Command>
|
||||
@@ -264,6 +273,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64ec.dll" "$(OutputPath)"</Command>
|
||||
@@ -296,6 +307,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect32.dll" "$(OutputPath)"</Command>
|
||||
@@ -328,6 +341,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect.dll" "$(OutputPath)"</Command>
|
||||
@@ -361,6 +376,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64.dll" "$(OutputPath)"</Command>
|
||||
@@ -394,6 +411,8 @@
|
||||
</ModuleDefinitionFile>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
|
||||
<ImportLibrary>$(OutDir)$(TargetName).dll.lib</ImportLibrary>
|
||||
<ProgramDatabaseFile>$(OutDir)$(TargetName).dll.pdb</ProgramDatabaseFile>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>COPY /Y "$(ProjectDir)..\..\bin\mimalloc-redirect-arm64ec.dll" "$(OutputPath)"</Command>
|
||||
@@ -408,6 +427,7 @@
|
||||
<ClInclude Include="..\..\include\mimalloc-etw.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc-new-delete.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc-override.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc-stats.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc\atomic.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc\internal.h" />
|
||||
<ClInclude Include="..\..\include\mimalloc\prim.h" />
|
||||
@@ -438,15 +458,15 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\alloc-posix.c" />
|
||||
<ClCompile Include="..\..\src\alloc.c" />
|
||||
<ClCompile Include="..\..\src\arena-abandoned.c">
|
||||
<ClCompile Include="..\..\src\arena-abandon.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena.c" />
|
||||
<ClCompile Include="..\..\src\bitmap.c" />
|
||||
@@ -482,9 +502,6 @@
|
||||
<ClCompile Include="..\..\src\segment.c" />
|
||||
<ClCompile Include="..\..\src\stats.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\include\mimalloc-etw-gen.man" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
<ClCompile Include="..\..\src\arena.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena-abandoned.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\bitmap.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
@@ -61,6 +58,9 @@
|
||||
<ClCompile Include="..\..\src\stats.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\arena-abandon.c">
|
||||
<Filter>Sources</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\include\mimalloc\atomic.h">
|
||||
@@ -96,6 +96,9 @@
|
||||
<ClInclude Include="..\..\include\mimalloc\prim.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\include\mimalloc-stats.h">
|
||||
<Filter>Headers</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Headers">
|
||||
@@ -105,9 +108,4 @@
|
||||
<UniqueIdentifier>{94b40bdc-a741-45dd-81aa-c05fabcd2970}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\include\mimalloc-etw-gen.man">
|
||||
<Filter>Sources</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,355 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|ARM64EC">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64EC</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64EC">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64EC</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{FEF7869F-750E-4C21-A04D-22707CC66879}</ProjectGuid>
|
||||
<RootNamespace>mimalloc-test-override-dep</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
<ProjectName>mimalloc-test-override-dep</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">
|
||||
<OutDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(ProjectDir)..\..\out\msvc-$(Platform)\$(ProjectName)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnabled>false</VcpkgEnabled>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent />
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent />
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent />
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64EC'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<ExceptionHandling>Sync</ExceptionHandling>
|
||||
<CompileAs>Default</CompileAs>
|
||||
<SupportJustMyCode>false</SupportJustMyCode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent />
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);NDEBUG</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);NDEBUG</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);NDEBUG</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64EC'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>..\..\include</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_MBCS;%(PreprocessorDefinitions);NDEBUG</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EntryPointSymbol>
|
||||
</EntryPointSymbol>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>
|
||||
</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\test\main-override-dep.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\test\main-override-dep.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Loaded 100 of 341 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user