From cee6412e3df313c0315db8351e90597e9d73d942 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Sat, 20 Nov 2021 19:01:18 +0900 Subject: [PATCH] [Mach-O] Add -rpath --- macho/cmdline.cc | 3 +++ macho/macho.h | 6 ++++++ macho/mold.h | 3 ++- macho/output-chunks.cc | 21 ++++++++++++++++++++- test/macho/rpath.sh | 19 +++++++++++++++++++ 5 files changed, 50 insertions(+), 2 deletions(-) create mode 100755 test/macho/rpath.sh diff --git a/macho/cmdline.cc b/macho/cmdline.cc index ef9b728a..b9e4a6b9 100644 --- a/macho/cmdline.cc +++ b/macho/cmdline.cc @@ -29,6 +29,7 @@ Options: -pagezero_size Specify the size of the __PAGEZERO segment -platform_version Set platform, platform version and SDK version + -rpath Add PATH to the runpath search path list -syslibroot Prepend DIR to library search paths -t Print out each file the linker loads -v Report version information)"; @@ -174,6 +175,8 @@ void parse_nonpositional_args(Context &ctx, ctx.arg.platform = parse_platform(ctx, arg); ctx.arg.platform_min_version = parse_version(ctx, arg2); ctx.arg.platform_sdk_version = parse_version(ctx, arg3); + } else if (read_arg("-rpath")) { + ctx.arg.rpath.push_back(std::string(arg)); } else if (read_arg("-syslibroot")) { ctx.arg.syslibroot.push_back(std::string(arg)); } else if (read_flag("-t")) { diff --git a/macho/macho.h b/macho/macho.h index 04d9dd71..08b2c195 100644 --- a/macho/macho.h +++ b/macho/macho.h @@ -475,6 +475,12 @@ struct UUIDCommand { u8 uuid[16]; }; +struct RpathCommand { + u32 cmd; + u32 cmdsize; + u32 path_off; +}; + struct LinkEditDataCommand { u32 cmd; u32 cmdsize; diff --git a/macho/mold.h b/macho/mold.h index 6580ad16..927f022c 100644 --- a/macho/mold.h +++ b/macho/mold.h @@ -733,8 +733,9 @@ struct Context { std::string entry = "_main"; std::string map; std::string output; - std::vector syslibroot; std::vector library_paths; + std::vector rpath; + std::vector syslibroot; } arg; std::vector cmdline_args; diff --git a/macho/output-chunks.cc b/macho/output-chunks.cc index a896b23f..e1a19f3d 100644 --- a/macho/output-chunks.cc +++ b/macho/output-chunks.cc @@ -159,6 +159,18 @@ static std::vector create_load_dylib_cmd(Context &ctx, std::string_view name return buf; } +static std::vector create_rpath_cmd(Context &ctx, std::string_view name) { + i64 size = sizeof(RpathCommand) + name.size() + 1; // +1 for NUL + std::vector buf(align_to(size, 8)); + RpathCommand &cmd = *(RpathCommand *)buf.data(); + + cmd.cmd = LC_RPATH; + cmd.cmdsize = buf.size(); + cmd.path_off = sizeof(cmd); + write_string(buf.data() + sizeof(cmd), name); + return buf; +} + static std::vector create_function_starts_cmd(Context &ctx) { std::vector buf(sizeof(LinkEditDataCommand)); LinkEditDataCommand &cmd = *(LinkEditDataCommand *)buf.data(); @@ -232,13 +244,20 @@ static std::pair> create_load_commands(Context &ctx) { vec.push_back(create_build_version_cmd(ctx)); vec.push_back(create_source_version_cmd(ctx)); vec.push_back(create_main_cmd(ctx)); + vec.push_back(create_function_starts_cmd(ctx)); + for (DylibFile *dylib : ctx.dylibs) vec.push_back(create_load_dylib_cmd(ctx, dylib->install_name)); - vec.push_back(create_function_starts_cmd(ctx)); + + for (std::string_view rpath : ctx.arg.rpath) + vec.push_back(create_rpath_cmd(ctx, rpath)); + if (!ctx.data_in_code.contents.empty()) vec.push_back(create_data_in_code_cmd(ctx)); + if (ctx.arg.adhoc_codesign) vec.push_back(create_code_signature_cmd(ctx)); + return {vec.size(), flatten(vec)}; } diff --git a/test/macho/rpath.sh b/test/macho/rpath.sh new file mode 100755 index 00000000..21a74608 --- /dev/null +++ b/test/macho/rpath.sh @@ -0,0 +1,19 @@ +#!/bin/bash +set -e +cd $(dirname $0) +mold=`pwd`/../../ld64.mold +echo -n "Testing $(basename -s .sh $0) ... " +t=$(pwd)/../../out/test/macho/$(basename -s .sh $0) +mkdir -p $t + +cat < $t/log + +grep -A3 'cmd LC_RPATH' $t/log | grep -q 'path foo' +grep -A3 'cmd LC_RPATH' $t/log | grep -q 'path bar' + +echo OK