1
1
mirror of https://github.com/rui314/mold.git synced 2024-09-20 09:27:45 +03:00

[Mach-O] Add -add_empty_section

This commit is contained in:
Rui Ueyama 2022-06-28 15:20:47 +08:00
parent 883320d5e7
commit b0c6aa9a0f
5 changed files with 83 additions and 14 deletions

View File

@ -20,6 +20,8 @@ Options:
-U <SYMBOL> Allow a symbol to be undefined -U <SYMBOL> Allow a symbol to be undefined
-Z Do not search the standard directories when -Z Do not search the standard directories when
searching for libraries and frameworks searching for libraries and frameworks
-add_empty_section <SEGNAME> <SECTNAME>
Add an empty section
-adhoc_codesign Add ad-hoc code signature to the output file -adhoc_codesign Add ad-hoc code signature to the output file
-no_adhoc_codesign -no_adhoc_codesign
-all_load Include all objects from static archives -all_load Include all objects from static archives
@ -194,6 +196,18 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
return false; return false;
}; };
auto read_arg2 = [&](std::string name) {
if (args[i] == name) {
if (args.size() <= i + 2)
Fatal(ctx) << "option -" << name << ": argument missing";
arg = args[i + 1];
arg2 = args[i + 2];
i += 3;
return true;
}
return false;
};
auto read_arg3 = [&](std::string name) { auto read_arg3 = [&](std::string name) {
if (args[i] == name) { if (args[i] == name) {
if (args.size() <= i + 3) if (args.size() <= i + 3)
@ -261,6 +275,8 @@ std::vector<std::string> parse_nonpositional_args(Context<E> &ctx) {
ctx.arg.ObjC = true; ctx.arg.ObjC = true;
} else if (read_arg("-U")) { } else if (read_arg("-U")) {
ctx.arg.U.push_back(std::string(arg)); ctx.arg.U.push_back(std::string(arg));
} else if (read_arg2("-add_empty_section")) {
ctx.arg.add_empty_section.push_back({arg, arg2});
} else if (read_flag("-adhoc_codesign")) { } else if (read_flag("-adhoc_codesign")) {
ctx.arg.adhoc_codesign = true; ctx.arg.adhoc_codesign = true;
} else if (read_flag("-no_adhoc_codesign")) { } else if (read_flag("-no_adhoc_codesign")) {

View File

@ -392,7 +392,14 @@ template <typename E>
static void create_synthetic_chunks(Context<E> &ctx) { static void create_synthetic_chunks(Context<E> &ctx) {
Timer t(ctx, "create_synthetic_chunks"); Timer t(ctx, "create_synthetic_chunks");
// First, we add subsections specified by -order_file to output sections. // Handle -sectcreate
for (SectCreateOption arg : ctx.arg.sectcreate) {
MappedFile<Context<E>> *mf =
MappedFile<Context<E>>::must_open(ctx, std::string(arg.filename));
new SectCreateSection<E>(ctx, arg.segname, arg.sectname, mf->get_contents());
}
// We add subsections specified by -order_file to output sections.
for (std::string_view name : ctx.arg.order_file) for (std::string_view name : ctx.arg.order_file)
if (Symbol<E> *sym = get_symbol(ctx, name); sym->file) if (Symbol<E> *sym = get_symbol(ctx, name); sym->file)
if (Subsection<E> *subsec = sym->subsec) if (Subsection<E> *subsec = sym->subsec)
@ -416,6 +423,15 @@ static void create_synthetic_chunks(Context<E> &ctx) {
seg->chunks.push_back(chunk); seg->chunks.push_back(chunk);
} }
// Handle -add_empty_section
for (AddEmptySectionOption &opt : ctx.arg.add_empty_section) {
if (!section_exists(ctx, opt.segname, opt.sectname)) {
OutputSegment<E> *seg = OutputSegment<E>::get_instance(ctx, opt.segname);
Chunk<E> *sec = new SectCreateSection<E>(ctx, opt.segname, opt.sectname, {});
seg->chunks.push_back(sec);
}
}
// Sort segments and output sections. // Sort segments and output sections.
sort(ctx.segments, compare_segments<E>); sort(ctx.segments, compare_segments<E>);
@ -423,6 +439,15 @@ static void create_synthetic_chunks(Context<E> &ctx) {
sort(seg->chunks, compare_chunks<E>); sort(seg->chunks, compare_chunks<E>);
} }
template <typename E>
static bool section_exists(Context<E> &ctx, std::string_view segname,
std::string_view sectname) {
for (Chunk<E> *chunk : ctx.chunks)
if (chunk->hdr.match(segname, sectname))
return true;
return false;
}
template <typename E> template <typename E>
static void scan_unwind_info(Context<E> &ctx) { static void scan_unwind_info(Context<E> &ctx) {
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) { tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
@ -822,15 +847,6 @@ static int do_main(int argc, char **argv) {
tbb::global_control tbb_cont(tbb::global_control::max_allowed_parallelism, tbb::global_control tbb_cont(tbb::global_control::max_allowed_parallelism,
ctx.arg.thread_count); ctx.arg.thread_count);
// Handle -sectcreate
for (SectCreateOption arg : ctx.arg.sectcreate) {
MappedFile<Context<E>> *mf =
MappedFile<Context<E>>::must_open(ctx, std::string(arg.filename));
SectCreateSection<E> *sec =
new SectCreateSection<E>(ctx, arg.segname, arg.sectname, mf->get_contents());
ctx.chunk_pool.emplace_back(sec);
}
if (ctx.arg.adhoc_codesign) if (ctx.arg.adhoc_codesign)
ctx.code_sig.reset(new CodeSignatureSection<E>(ctx)); ctx.code_sig.reset(new CodeSignatureSection<E>(ctx));

View File

@ -707,10 +707,7 @@ template <typename E>
class SectCreateSection : public Chunk<E> { class SectCreateSection : public Chunk<E> {
public: public:
SectCreateSection(Context<E> &ctx, std::string_view seg, std::string_view sect, SectCreateSection(Context<E> &ctx, std::string_view seg, std::string_view sect,
std::string_view contents) std::string_view contents);
: Chunk<E>(ctx, seg, sect), contents(contents) {
this->hdr.size = contents.size();
}
void copy_buf(Context<E> &ctx) override; void copy_buf(Context<E> &ctx) override;
@ -795,6 +792,11 @@ void create_range_extension_thunks(Context<ARM64> &ctx, OutputSection<ARM64> &os
enum UuidKind { UUID_NONE, UUID_HASH, UUID_RANDOM }; enum UuidKind { UUID_NONE, UUID_HASH, UUID_RANDOM };
struct AddEmptySectionOption {
std::string_view segname;
std::string_view sectname;
};
struct SectCreateOption { struct SectCreateOption {
std::string_view segname; std::string_view segname;
std::string_view sectname; std::string_view sectname;
@ -870,6 +872,7 @@ struct Context {
std::string map; std::string map;
std::string object_path_lto; std::string object_path_lto;
std::string output = "a.out"; std::string output = "a.out";
std::vector<AddEmptySectionOption> add_empty_section;
std::vector<SectCreateOption> sectcreate; std::vector<SectCreateOption> sectcreate;
std::vector<std::string> U; std::vector<std::string> U;
std::vector<std::string> framework_paths; std::vector<std::string> framework_paths;

View File

@ -1530,6 +1530,15 @@ void ThreadPtrsSection<E>::copy_buf(Context<E> &ctx) {
buf[i] = sym.get_addr(ctx); buf[i] = sym.get_addr(ctx);
} }
template <typename E>
SectCreateSection<E>::SectCreateSection(Context<E> &ctx, std::string_view seg,
std::string_view sect,
std::string_view contents)
: Chunk<E>(ctx, seg, sect), contents(contents) {
this->hdr.size = contents.size();
ctx.chunk_pool.emplace_back(this);
}
template <typename E> template <typename E>
void SectCreateSection<E>::copy_buf(Context<E> &ctx) { void SectCreateSection<E>::copy_buf(Context<E> &ctx) {
write_string(ctx.buf + this->hdr.offset, contents); write_string(ctx.buf + this->hdr.offset, contents);

25
test/macho/add-empty-section.sh Executable file
View File

@ -0,0 +1,25 @@
#!/bin/bash
export LC_ALL=C
set -e
CC="${TEST_CC:-cc}"
CXX="${TEST_CXX:-c++}"
GCC="${TEST_GCC:-gcc}"
GXX="${TEST_GXX:-g++}"
OBJDUMP="${OBJDUMP:-objdump}"
MACHINE="${MACHINE:-$(uname -m)}"
testname=$(basename "$0" .sh)
echo -n "Testing $testname ... "
cd "$(dirname "$0")"/../..
t=out/test/macho/$testname
mkdir -p $t
cat <<EOF | $CC -o $t/a.o -c -xc -
int main() {}
EOF
clang --ld-path=./ld64 -o $t/exe $t/a.o -Wl,-add_empty_section,__FOO,__foo
otool -l $t/exe | grep -q 'segname __FOO'
otool -l $t/exe | grep -q 'sectname __foo'
echo OK