From d8c64c2ea72d3cab4cd6550f6758c1d4576c1338 Mon Sep 17 00:00:00 2001 From: Carlo Cabrera <30379873+carlocab@users.noreply.github.com> Date: Thu, 20 Oct 2022 00:04:05 +0800 Subject: [PATCH] [Mach-O] Support `-flat_namespace` flag This implements the minimum necessary to support the `-flat_namespace` flag. I have not added this flag to the `-help` text, because I'm not certain this is faithful to ld64's behaviour under this flag. From `man ld`: -flat_namespace Alters how symbols are resolved at build time and runtime. With -two_levelnamespace (the default), the linker only searches dylibs on the command line for symbols, and records in which dylib they were found. With -flat_namespace, the linker searches all dylibs on the command line and all dylibs those original dylibs depend on. The linker does not record which dylib an external symbol came from, so at runtime dyld again searches all images and uses the first definition it finds. In addition, any undefines in loaded flat_namespace dylibs must be resolvable at build time. However, I believe what is done here is enough to approximate what build systems expect to happen when they pass `-flat_namespace` to the linker. Closes #785. Signed-off-by: Carlo Cabrera <30379873+carlocab@users.noreply.github.com> --- macho/cmdline.cc | 2 ++ macho/mold.h | 1 + macho/output-chunks.cc | 5 ++++- test/macho/flat_namespace.sh | 19 +++++++++++++++++++ 4 files changed, 26 insertions(+), 1 deletion(-) create mode 100755 test/macho/flat_namespace.sh diff --git a/macho/cmdline.cc b/macho/cmdline.cc index 835bbdddbe..688f231781 100644 --- a/macho/cmdline.cc +++ b/macho/cmdline.cc @@ -354,6 +354,8 @@ std::vector parse_nonpositional_args(Context &ctx) { ctx.arg.dependency_info = arg; } else if (read_flag("-dylib")) { ctx.output_type = MH_DYLIB; + } else if (read_flag("-flat_namespace")) { + ctx.arg.flat_namespace = true; } else if (read_hex("-headerpad")) { ctx.arg.headerpad = hex_arg; } else if (read_flag("-headerpad_max_install_names")) { diff --git a/macho/mold.h b/macho/mold.h index ce97683593..6e535555aa 100644 --- a/macho/mold.h +++ b/macho/mold.h @@ -869,6 +869,7 @@ struct Context { bool dynamic = true; bool export_dynamic = false; bool fatal_warnings = false; + bool flat_namespace = false; bool function_starts = true; bool ignore_optimization_hints = true; bool mark_dead_strippable_dylib = false; diff --git a/macho/output-chunks.cc b/macho/output-chunks.cc index 2f0b685de8..61b2e5bd37 100644 --- a/macho/output-chunks.cc +++ b/macho/output-chunks.cc @@ -346,7 +346,7 @@ void OutputMachHeader::copy_buf(Context &ctx) { mhdr.filetype = ctx.output_type; mhdr.ncmds = cmds.size(); mhdr.sizeofcmds = flatten(cmds).size(); - mhdr.flags = MH_TWOLEVEL | MH_NOUNDEFS | MH_DYLDLINK | MH_PIE; + mhdr.flags = MH_NOUNDEFS | MH_DYLDLINK | MH_PIE; if (has_tlv(ctx)) mhdr.flags |= MH_HAS_TLV_DESCRIPTORS; @@ -357,6 +357,9 @@ void OutputMachHeader::copy_buf(Context &ctx) { if (ctx.arg.mark_dead_strippable_dylib) mhdr.flags |= MH_DEAD_STRIPPABLE_DYLIB; + if (!ctx.arg.flat_namespace) + mhdr.flags |= MH_TWOLEVEL; + write_vector(buf + sizeof(mhdr), flatten(cmds)); } diff --git a/test/macho/flat_namespace.sh b/test/macho/flat_namespace.sh new file mode 100755 index 0000000000..ae4c72eb18 --- /dev/null +++ b/test/macho/flat_namespace.sh @@ -0,0 +1,19 @@ +#!/bin/bash +export LC_ALL=C +set -e +testname=$(basename "$0" .sh) +echo -n "Testing $testname ... " +t=out/test/macho/$(uname -m)/$testname +mkdir -p $t + +cat <