1
1
mirror of https://github.com/rui314/mold.git synced 2024-11-10 10:57:55 +03:00

[Mach-O] Support -dylib

This commit is contained in:
Rui Ueyama 2021-11-29 18:12:48 +09:00
parent 39fbd5b29c
commit 4998a130e5
6 changed files with 76 additions and 16 deletions

View File

@ -23,8 +23,10 @@ Options:
-arch <ARCH_NAME> Specify target architecture
-dead_strip Remove unreachable functions and data
-demangle Demangle C++ symbols in log messages (default)
-dylib Produce a dynamic library
-dynamic Link against dylibs (default)
-e <SYMBOL> Specify the entry point of a main executable
-execute Produce an executable (default)
-filelist <FILE>[,<DIR>] Specify the list of input file names
-framework <NAME>,[,<SUFFIX>]
Search for a given framework
@ -176,6 +178,8 @@ void parse_nonpositional_args(Context &ctx,
ctx.arg.dead_strip = true;
} else if (read_flag("-demangle")) {
ctx.arg.demangle = true;
} else if (read_flag("-dylib")) {
ctx.output_type = MH_DYLIB;
} else if (read_arg("-headerpad")) {
size_t pos;
ctx.arg.headerpad = std::stoi(std::string(arg), &pos, 16);
@ -185,6 +189,8 @@ void parse_nonpositional_args(Context &ctx,
ctx.arg.dynamic = true;
} else if (read_arg("-e")) {
ctx.arg.entry = arg;
} else if (read_flag("-execute")) {
ctx.output_type = MH_EXECUTE;
} else if (read_arg("-fatal_warnings")) {
} else if (read_arg("-filelist")) {
remaining.push_back("-filelist");

View File

@ -5,9 +5,19 @@ namespace mold::macho {
static std::vector<Subsection *> collect_root_set(Context &ctx) {
std::vector<Subsection *> rootset;
if (Symbol *sym = intern(ctx, ctx.arg.entry))
if (sym->subsec)
auto mark = [&](Symbol *sym) {
if (sym && sym->subsec)
rootset.push_back(sym->subsec);
};
mark(intern(ctx, ctx.arg.entry));
if (ctx.output_type == MH_DYLIB)
for (ObjectFile *file : ctx.objs)
for (Symbol *sym : file->syms)
if (sym->file == file && sym->is_extern)
mark(sym);
return rootset;
}

View File

@ -34,10 +34,20 @@ static void create_internal_file(Context &ctx) {
add("__dyld_private");
Symbol *sym = add("__mh_execute_header");
sym->is_extern = true;
sym->referenced_dynamically = true;
sym->value = ctx.arg.pagezero_size;
switch (ctx.output_type) {
case MH_EXECUTE: {
Symbol *sym = add("__mh_execute_header");
sym->is_extern = true;
sym->referenced_dynamically = true;
sym->value = ctx.arg.pagezero_size;
break;
}
case MH_DYLIB:
add("__mh_dylib_header");
break;
default:
unreachable();
}
}
static bool compare_segments(const std::unique_ptr<OutputSegment> &a,
@ -193,6 +203,7 @@ static i64 assign_offsets(Context &ctx) {
static void fix_synthetic_symbol_values(Context &ctx) {
intern(ctx, "__dyld_private")->value = ctx.data->hdr.addr;
intern(ctx, "__mh_dylib_header")->value = ctx.data->hdr.addr;
}
MappedFile<Context> *find_framework(Context &ctx, std::string name) {
@ -366,7 +377,7 @@ int main(int argc, char **argv) {
for (DylibFile *dylib : ctx.dylibs)
dylib->resolve_symbols(ctx);
if (!intern(ctx, ctx.arg.entry)->file)
if (ctx.output_type == MH_EXECUTE && !intern(ctx, ctx.arg.entry)->file)
Error(ctx) << "undefined entry point symbol: " << ctx.arg.entry;
create_internal_file(ctx);

View File

@ -723,14 +723,15 @@ struct Context {
bool dead_strip = true;
bool deduplicate = true;
bool demangle = false;
bool dylib = false;
bool dynamic = true;
bool fatal_warnings = false;
bool trace = false;
i64 headerpad = 256;
i64 pagezero_size = 0x100000000;
i64 platform = PLATFORM_MACOS;
i64 platform_min_version = 0;
i64 platform_sdk_version = 0;
i64 headerpad = 256;
i64 pagezero_size = 0x100000000;
std::string chroot;
std::string entry = "_main";
std::string map;
@ -742,6 +743,7 @@ struct Context {
} arg;
std::vector<std::string_view> cmdline_args;
u32 output_type = MH_EXECUTE;
bool has_error = false;

View File

@ -193,6 +193,17 @@ static std::vector<u8> create_data_in_code_cmd(Context &ctx) {
return buf;
}
static std::vector<u8> create_id_dylib_cmd(Context &ctx) {
std::vector<u8> buf(sizeof(DylibCommand) + ctx.arg.output.size() + 1);
DylibCommand &cmd = *(DylibCommand *)buf.data();
cmd.cmd = LC_ID_DYLIB;
cmd.cmdsize = buf.size();
cmd.nameoff = sizeof(cmd);
write_string(buf.data() + sizeof(cmd), ctx.arg.output);
return buf;
}
static std::vector<u8> create_code_signature_cmd(Context &ctx) {
std::vector<u8> buf(sizeof(LinkEditDataCommand));
LinkEditDataCommand &cmd = *(LinkEditDataCommand *)buf.data();
@ -239,11 +250,9 @@ static std::pair<i64, std::vector<u8>> create_load_commands(Context &ctx) {
vec.push_back(create_dyld_info_only_cmd(ctx));
vec.push_back(create_symtab_cmd(ctx));
vec.push_back(create_dysymtab_cmd(ctx));
vec.push_back(create_dylinker_cmd(ctx));
vec.push_back(create_uuid_cmd(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)
@ -255,6 +264,18 @@ static std::pair<i64, std::vector<u8>> create_load_commands(Context &ctx) {
if (!ctx.data_in_code.contents.empty())
vec.push_back(create_data_in_code_cmd(ctx));
switch (ctx.output_type) {
case MH_EXECUTE:
vec.push_back(create_dylinker_cmd(ctx));
vec.push_back(create_main_cmd(ctx));
break;
case MH_DYLIB:
vec.push_back(create_id_dylib_cmd(ctx));
break;
default:
unreachable();
}
if (ctx.arg.adhoc_codesign)
vec.push_back(create_code_signature_cmd(ctx));
@ -286,7 +307,7 @@ void OutputMachHeader::copy_buf(Context &ctx) {
mhdr.magic = 0xfeedfacf;
mhdr.cputype = CPU_TYPE_X86_64;
mhdr.cpusubtype = CPU_SUBTYPE_X86_64_ALL;
mhdr.filetype = MH_EXECUTE;
mhdr.filetype = ctx.output_type;
mhdr.ncmds = ncmds;
mhdr.sizeofcmds = cmds.size();
mhdr.flags = MH_TWOLEVEL | MH_NOUNDEFS | MH_DYLDLINK | MH_PIE;
@ -294,6 +315,9 @@ void OutputMachHeader::copy_buf(Context &ctx) {
if (has_tlv(ctx))
mhdr.flags |= MH_HAS_TLV_DESCRIPTORS;
if (ctx.output_type == MH_DYLIB)
mhdr.flags |= MH_NO_REEXPORTED_DYLIBS;
write_vector(buf + sizeof(mhdr), cmds);
}
@ -659,7 +683,12 @@ i64 ExportEncoder::finish() {
return a.name < b.name;
});
root = construct_trie(entries, 0);
TrieNode trie = construct_trie(entries, 0);
if (trie.prefix.empty())
root = std::move(trie);
else
root.children.push_back(std::move(trie));
i64 size = set_offset(root, 0);
for (;;) {

View File

@ -6,7 +6,7 @@ echo -n "Testing $(basename -s .sh $0) ... "
t=$(pwd)/../../out/test/macho/$(basename -s .sh $0)
mkdir -p $t
cat <<EOF | cc -shared -o $t/a.dylib -xc -
cat <<EOF | cc -c -o $t/a.o -xc -
#include <stdio.h>
char world[] = "world";
@ -15,7 +15,9 @@ char *hello() {
}
EOF
cat <<EOF | cc -o $t/b.o -c -xc -
clang -fuse-ld=$mold -o $t/b.dylib -shared $t/a.o
cat <<EOF | cc -o $t/c.o -c -xc -
#include <stdio.h>
char *hello();
@ -26,7 +28,7 @@ int main() {
}
EOF
clang -fuse-ld=$mold -o $t/exe $t/b.o $t/a.dylib
clang -fuse-ld=$mold -o $t/exe $t/c.o $t/b.dylib
$t/exe | grep -q 'Hello world'
echo OK