distribution/packages/devel/mold/patches/mold-999.01-fix-strip-on-armv7.patch

164 lines
5.3 KiB
Diff

From 610042a8e927106cb2d852fba2a90faa0d0e050f Mon Sep 17 00:00:00 2001
From: Rui Ueyama <ruiu@bluewhale.systems>
Date: Fri, 21 Oct 2022 07:08:09 +0800
Subject: [PATCH] [ELF] Set .ARM.exidx's sh_link to .text
GNU binutil's strip command doesn't like an .ARM.exidx section with
sh_link set to 0. arm-linux-gnueabihf-strip actually crashes on my
machine when the command is run on such a file.
https://github.com/rui314/mold/issues/801
---
elf/arch-arm32.cc | 56 +++++++++++++++++++++++++++++--------------
elf/mold.h | 2 +-
elf/output-chunks.cc | 4 ++--
elf/passes.cc | 2 +-
test/elf/exception.sh | 8 +++++++
5 files changed, 50 insertions(+), 22 deletions(-)
diff --git a/elf/arch-arm32.cc b/elf/arch-arm32.cc
index 46e45d43d..bea510763 100644
--- a/elf/arch-arm32.cc
+++ b/elf/arch-arm32.cc
@@ -552,14 +552,6 @@ void RangeExtensionThunk<E>::copy_buf(Context<E> &ctx) {
}
}
-template <typename E>
-static OutputSection<E> *find_exidx_section(Context<E> &ctx) {
- for (std::unique_ptr<OutputSection<E>> &osec : ctx.output_sections)
- if (osec->shdr.sh_type == SHT_ARM_EXIDX)
- return osec.get();
- return nullptr;
-}
-
// ARM executables use an .ARM.exidx section to look up an exception
// handling record for the current instruction pointer. The table needs
// to be sorted by their addresses.
@@ -569,13 +561,7 @@ static OutputSection<E> *find_exidx_section(Context<E> &ctx) {
// likely that it's due to some historical reason.
//
// This function sorts .ARM.exidx records.
-void sort_arm_exidx(Context<E> &ctx) {
- Timer t(ctx, "sort_arm_exidx");
-
- OutputSection<E> *osec = find_exidx_section(ctx);
- if (!osec)
- return;
-
+static void sort_exidx(Context<E> &ctx, OutputSection<E> &osec) {
// .ARM.exidx records consists of a signed 31-bit relative address
// and a 32-bit value. The relative address indicates the start
// address of a function that the record covers. The value is one of
@@ -595,11 +581,11 @@ void sort_arm_exidx(Context<E> &ctx) {
ul32 val;
};
- if (osec->shdr.sh_size % sizeof(Entry))
+ if (osec.shdr.sh_size % sizeof(Entry))
Fatal(ctx) << "invalid .ARM.exidx section size";
- Entry *ent = (Entry *)(ctx.buf + osec->shdr.sh_offset);
- i64 num_entries = osec->shdr.sh_size / sizeof(Entry);
+ Entry *ent = (Entry *)(ctx.buf + osec.shdr.sh_offset);
+ i64 num_entries = osec.shdr.sh_size / sizeof(Entry);
// Entry's addresses are relative to themselves. In order to sort
// records by addresses, we first translate them so that the addresses
@@ -628,4 +614,38 @@ void sort_arm_exidx(Context<E> &ctx) {
});
}
+void fixup_arm_exidx_section(Context<E> &ctx) {
+ Timer t(ctx, "fixup_arm_exidx_section");
+
+ auto find_exidx = [&]() -> OutputSection<E> * {
+ for (std::unique_ptr<OutputSection<E>> &osec : ctx.output_sections)
+ if (osec->shdr.sh_type == SHT_ARM_EXIDX)
+ return osec.get();
+ return nullptr;
+ };
+
+ OutputSection<E> *exidx = find_exidx();
+ if (!exidx)
+ return;
+
+ // Sort .ARM.exidx contents
+ sort_exidx(ctx, *exidx);
+
+ // .ARM.exidx's sh_link should be set to the .text section index.
+ // Runtime doesn't care about it, but the binutils's strip command does.
+ if (ctx.shdr) {
+ auto find_text = [&]() -> OutputSection<E> * {
+ for (std::unique_ptr<OutputSection<E>> &osec : ctx.output_sections)
+ if (osec->name == ".text")
+ return osec.get();
+ return nullptr;
+ };
+
+ if (OutputSection<E> *text = find_exidx()) {
+ exidx->shdr.sh_link = text->shndx;
+ ctx.shdr->copy_buf(ctx);
+ }
+ }
+}
+
} // namespace mold::elf
diff --git a/elf/mold.h b/elf/mold.h
index 11938270e..c8bac2b4e 100644
--- a/elf/mold.h
+++ b/elf/mold.h
@@ -1434,7 +1434,7 @@ template <typename E> void write_dependency_file(Context<E> &);
// arch-arm32.cc
//
-void sort_arm_exidx(Context<ARM32> &ctx);
+void fixup_arm_exidx_section(Context<ARM32> &ctx);
//
// arch-riscv64.cc
diff --git a/elf/output-chunks.cc b/elf/output-chunks.cc
index 54562feb2..0d1d0dcfd 100644
--- a/elf/output-chunks.cc
+++ b/elf/output-chunks.cc
@@ -847,9 +847,9 @@ get_output_name(Context<E> &ctx, std::string_view name, u64 flags) {
if ((name == ".rodata" || name.starts_with(".rodata.")) && (flags & SHF_MERGE))
return (flags & SHF_STRINGS) ? ".rodata.str" : ".rodata.cst";
- if (name == ".ARM.exidx" || name.starts_with(".ARM.exidx."))
+ if (name.starts_with(".ARM.exidx"))
return ".ARM.exidx";
- if (name == ".ARM.extab" || name.starts_with(".ARM.extab."))
+ if (name.starts_with(".ARM.extab"))
return ".ARM.extab";
if (ctx.arg.z_keep_text_section_prefix) {
diff --git a/elf/passes.cc b/elf/passes.cc
index 713a06a84..4bffc3dbd 100644
--- a/elf/passes.cc
+++ b/elf/passes.cc
@@ -1102,7 +1102,7 @@ void copy_chunks(Context<E> &ctx) {
report_undef_errors(ctx);
if constexpr (std::is_same_v<E, ARM32>)
- sort_arm_exidx(ctx);
+ fixup_arm_exidx_section(ctx);
}
template <typename E>
diff --git a/test/elf/exception.sh b/test/elf/exception.sh
index 6832966f0..c584c99fa 100755
--- a/test/elf/exception.sh
+++ b/test/elf/exception.sh
@@ -65,3 +65,11 @@ if [ $MACHINE = x86_64 -o $MACHINE = aarch64 ]; then
$CXX -B. -o $t/exe10 $t/e.o -no-pie
$QEMU $t/exe10
fi
+
+$CXX -B. -o $t/exe11 $t/b.o -pie
+$STRIP $t/exe11
+$QEMU $t/exe11
+
+$CXX -B. -o $t/exe12 $t/c.o -no-pie
+$STRIP $t/exe12
+$QEMU $t/exe12