Compare commits

..
48 Commits
Author SHA1 Message Date
Rui Ueyama 57f5c77174 ARC 2025-04-15 16:49:41 +09:00
Rui Ueyama ac6f1ec18e Do not hide foo@@VER if both foo@@VER and foo are defined
Fixes https://github.com/rui314/mold/issues/1442
2025-04-15 12:28:31 +09:00
Rui Ueyama d19f822ec0 Simplify 2025-04-15 11:51:11 +09:00
Rui Ueyama a97a628ee8 Resolve versioned symbols early
Fixes https://github.com/rui314/mold/issues/1440
2025-04-11 14:46:27 +09:00
Rui Ueyama 2888aade4c Refactor 2025-04-10 12:59:13 +09:00
Rui Ueyama 0172f22ab5 Refactor 2025-04-07 17:25:28 +09:00
Rui Ueyama 418d4ff62a Fix CI 2025-04-07 11:26:18 +09:00
Rui Ueyama 5249edc57f Simplify 2025-04-07 10:37:08 +09:00
Rui Ueyama 1870845f88 Refactor 2025-04-07 09:07:12 +09:00
Rui Ueyama d15c41a8dd Process --repro early
If mold crashes before --repro is processed, no .repro.tar file is
created. So we want to process the option as early as possible.
2025-04-07 08:50:26 +09:00
Rui Ueyama b7c8a843b2 Ignore --mmap-output-file
For the sake of completeness, --mmap-output-file is ignored just like
--no-mmap-output-file is.
2025-04-03 16:57:37 +09:00
Rui Ueyama 9b77a7ea86 Fix CI 2025-04-03 16:02:20 +09:00
Rui Ueyama af396ad5d9 Add --audit and --depaudit
These are for the sake of compatibility with GNU ld.
2025-04-03 15:36:05 +09:00
Rui Ueyama a2ee7371d5 Handle -mllvm as a synonym for -plugin-opt
Related to https://github.com/rui314/mold/pull/1437
2025-04-03 09:26:17 +09:00
Rui Ueyama c9812cf09f Merge pull request #1436 from christycylee/ignore_no_mmap_output_file
Ignore no-mmap-output-file for compatibility.
2025-04-03 08:59:31 +09:00
Christy Lee e9c070a3c2 Ignore no-mmap-output-file for compatibility. 2025-04-02 11:39:53 -07:00
Rui Ueyama 02e75be9fa Simplify 2025-04-02 21:55:17 +09:00
Rui Ueyama d5609a9bb8 Fix CI 2025-04-02 18:28:37 +09:00
Rui Ueyama 5d24db5a64 Handle COMDAT symbols in LTO IR object files
Before 9306f69a61, we completely ignored
duplciate symbol errors in IR object files. After that commit, we've
been accidentally reporting duplicate comdat symbols as errors.

Fixes https://github.com/rui314/mold/issues/1434
2025-04-02 17:54:41 +09:00
Rui Ueyama aeec8baee5 Revert "Take r_delta into account when computing distance"
This reverts commit b74a771886
because it broke buildbots.
2025-04-02 10:48:57 +09:00
Rui Ueyama b74a771886 Take r_delta into account when computing distance 2025-04-01 16:56:21 +09:00
Rui Ueyama 0124058ef7 Refactor 2025-03-26 20:56:04 +09:00
Rui Ueyama e302a2509c Fix CI 2025-03-26 20:56:02 +09:00
Rui Ueyama f70db66373 Use std::ranges 2025-03-26 20:26:51 +09:00
Rui Ueyama 9c0cbc8e6c Fix R_AARCH64_PREL16 range 2025-03-25 18:01:38 +09:00
Rui Ueyama a9acbd6b6f Refactor 2025-03-24 16:03:52 +09:00
Rui Ueyama b9d65a5787 Update RV32 toolchain 2025-03-24 15:40:06 +09:00
Rui Ueyama 50766f1ad4 Remove endbr32 support
It looks like Linux is going to support CET only on x86-64 (i.e. endbr64),
and it is very unlikely that x86-32 will get CET support. So I'll remove
the instruction from the code we generate for x86-32.
2025-03-23 18:07:21 +09:00
Rui Ueyama 3496ad1291 Update comments 2025-03-22 13:39:54 +09:00
Rui Ueyama 8a3d374251 Simplify 2025-03-22 11:20:07 +09:00
Rui Ueyama 96b2710849 Fix CI 2025-03-20 16:32:29 +09:00
Rui Ueyama a43f3953f0 Do not create redundant range extension thunks
Previously, we created thunks for all PLT function calls.
2025-03-20 13:25:05 +09:00
Rui Ueyama 2bc6ddc41c Refactor 2025-03-19 11:18:15 +09:00
Rui Ueyama f6575d53c1 Report an error if CREL contains addends for REL-type targets
Fixes https://github.com/rui314/mold/issues/1430
2025-03-18 10:52:55 +09:00
Rui Ueyama bf1ec5ac8f Allow very large offsets in SHT_CREL 2025-03-14 15:32:38 +09:00
Rui Ueyama b291100cfe Refactor 2025-03-14 15:05:16 +09:00
Rui Ueyama c43a859a90 Support CREL as input section
Fixes https://github.com/rui314/mold/issues/1427
2025-03-13 15:17:11 +09:00
Rui Ueyama 6e3d0e3a3c Fix build failure on Windows 2025-03-12 14:24:11 +09:00
Rui Ueyama 790ce3f64d Downgrade mimalloc to 2.2.2
mimalloc 3.0.1 cannot be compiled on Windows, so we don't want to stick
with the 2.x series for the time being.
2025-03-12 14:05:35 +09:00
Rui Ueyama cbd7f74c2e Upgrade bundled xxhash to 0.8.3 2025-03-12 13:38:26 +09:00
Rui Ueyama 3fe25fc69d Upgrade bundled mimalloc to 3.0.1 2025-03-12 13:34:39 +09:00
Rui Ueyama 823ef09585 Upgrade bundled blake3 to 1.6.1 2025-03-12 13:32:26 +09:00
Rui Ueyama f20f57060a Upgrade bundled zstd to 1.5.7 2025-03-12 11:44:12 +09:00
Rui Ueyama 0061d53409 Merge pull request #1425 from christycylee/buck_files
Remove extraneous build files
2025-03-11 10:35:56 +09:00
Rui Ueyama 82affb94d8 Fix out-of-bound memory access
Related to https://github.com/rui314/mold/issues/1426
2025-03-10 14:54:17 +09:00
Rui Ueyama 4f782fb7dc Refactor 2025-03-08 17:13:48 +09:00
Rui Ueyama e9eb6020a6 Skip if textrel is prohibited by default 2025-03-08 10:47:29 +09:00
Christy Lee 23a662cbb9 Remove extraneous build files 2025-03-07 14:23:22 -08:00
341 changed files with 12324 additions and 6985 deletions

No files matched your search

+1
View File
@@ -70,6 +70,7 @@ jobs:
- gentoo/stage3
- opensuse/tumbleweed
- ubuntu:22.04
- ubuntu:25.04
runs-on: ubuntu-latest
container: ${{ matrix.distro }}
steps:
+1 -1
View File
@@ -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
View File
@@ -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
Executable
+29
View File
@@ -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
+1 -2
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+96 -1
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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> &);
+8
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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> &);
+5 -6
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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'
+15
View File
@@ -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]'
+29
View File
@@ -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'
+26
View File
@@ -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
+19
View File
@@ -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'
+24
View File
@@ -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
+22
View File
@@ -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'
+22
View File
@@ -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
+19
View File
@@ -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'
+3
View File
@@ -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
View File
@@ -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
View File
@@ -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$'
+3 -3
View File
@@ -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
View File
@@ -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",
]
+2 -2
View File
@@ -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
View File
@@ -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();
+1 -1
View File
@@ -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);
+4 -2
View File
@@ -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"
}
+1 -1
View File
@@ -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
)
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+18 -16
View File
@@ -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 {
+51 -37
View File
@@ -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 {
+39 -27
View File
@@ -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 {
+39 -27
View File
@@ -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 {
+3 -18
View File
@@ -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))
}
}
+7
View File
@@ -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
+14 -4
View File
@@ -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]
+1
View File
@@ -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.
+3
View File
@@ -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
+133 -73
View File
@@ -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
View File
@@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+22 -6
View File
@@ -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)
+2 -2
View File
@@ -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.
+63
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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