diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-03-13 01:01:26 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-03-13 01:01:26 -0400 |
| commit | 26b0d34361912a4b521d7202310647909cf7cb44 (patch) | |
| tree | b0d45aa88eaf7cca4b5073c298c6f3a7ba9b7419 /src/link.cpp | |
| parent | 761356209bd64ed655be96c0cf11869f2ff5f530 (diff) | |
| parent | c73cd05468fba4bba5762a654aacdd9d90ecd272 (diff) | |
| download | zig-26b0d34361912a4b521d7202310647909cf7cb44.tar.gz zig-26b0d34361912a4b521d7202310647909cf7cb44.zip | |
Merge pull request #2055 from ziglang/musl
support musl for all compatible targets
Diffstat (limited to 'src/link.cpp')
| -rw-r--r-- | src/link.cpp | 307 |
1 files changed, 287 insertions, 20 deletions
diff --git a/src/link.cpp b/src/link.cpp index deb3fd2155..b3aa94f0ee 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -10,7 +10,7 @@ #include "codegen.hpp" #include "analyze.hpp" #include "compiler.hpp" - +#include "install_files.h" struct LinkJob { CodeGen *codegen; @@ -53,6 +53,10 @@ static bool target_is_glibc(CodeGen *g) { return g->zig_target->os == OsLinux && target_abi_is_gnu(g->zig_target->abi); } +static bool target_is_musl(CodeGen *g) { + return g->zig_target->os == OsLinux && target_abi_is_musl(g->zig_target->abi); +} + static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFile *c_file) { CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr); codegen_set_out_name(child_gen, buf_create_from_str(name)); @@ -63,6 +67,14 @@ static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFil return buf_ptr(&child_gen->output_file_path); } +static const char *build_asm_object(CodeGen *parent_gen, const char *name, Buf *file) { + CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr); + codegen_set_out_name(child_gen, buf_create_from_str(name)); + codegen_add_assembly(child_gen, file); + codegen_build_and_link(child_gen); + return buf_ptr(&child_gen->output_file_path); +} + static const char *path_from_zig_lib(CodeGen *g, const char *dir, const char *subpath) { Buf *dir1 = buf_alloc(); os_path_join(g->zig_lib_dir, buf_create_from_str(dir), dir1); @@ -368,6 +380,233 @@ static const char *glibc_start_asm_path(CodeGen *parent, const char *file) { return buf_ptr(&result); } +static const char *musl_arch_name(const ZigTarget *target) { + switch (target->arch) { + case ZigLLVM_aarch64: + case ZigLLVM_aarch64_be: + return "aarch64"; + case ZigLLVM_arm: + case ZigLLVM_armeb: + return "arm"; + case ZigLLVM_mips: + case ZigLLVM_mipsel: + return "mips"; + case ZigLLVM_mips64el: + case ZigLLVM_mips64: + return "mips64"; + case ZigLLVM_ppc: + return "powerpc"; + case ZigLLVM_ppc64: + case ZigLLVM_ppc64le: + return "powerpc64"; + case ZigLLVM_systemz: + return "s390x"; + case ZigLLVM_x86: + return "i386"; + case ZigLLVM_x86_64: + return "x86_64"; + default: + zig_unreachable(); + } +} + +static Buf *musl_start_asm_path(CodeGen *parent, const char *file) { + return buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "crt" OS_SEP "%s" OS_SEP "%s", + buf_ptr(parent->zig_lib_dir), musl_arch_name(parent->zig_target), file); +} + +static void musl_add_cc_args(CodeGen *parent, CFile *c_file) { + c_file->args.append("-std=c99"); + c_file->args.append("-ffreestanding"); + // Musl adds these args to builds with gcc but clang does not support them. + //c_file->args.append("-fexcess-precision=standard"); + //c_file->args.append("-frounding-math"); + c_file->args.append("-Wa,--noexecstack"); + c_file->args.append("-D_XOPEN_SOURCE=700"); + + c_file->args.append("-I"); + c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "arch" OS_SEP "%s", + buf_ptr(parent->zig_lib_dir), musl_arch_name(parent->zig_target)))); + + c_file->args.append("-I"); + c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "arch" OS_SEP "generic", + buf_ptr(parent->zig_lib_dir)))); + + c_file->args.append("-I"); + c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "src" OS_SEP "internal", + buf_ptr(parent->zig_lib_dir)))); + + c_file->args.append("-I"); + c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "musl" OS_SEP "src" OS_SEP "include", + buf_ptr(parent->zig_lib_dir)))); + + c_file->args.append("-I"); + c_file->args.append(buf_ptr(buf_sprintf( + "%s" OS_SEP "libc" OS_SEP "include" OS_SEP "%s-%s-%s", + buf_ptr(parent->zig_lib_dir), + target_arch_name(parent->zig_target->arch), + target_os_name(parent->zig_target->os), + target_abi_name(parent->zig_target->abi)))); + + c_file->args.append("-I"); + c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "generic-musl", + buf_ptr(parent->zig_lib_dir)))); + + c_file->args.append("-Os"); + c_file->args.append("-fomit-frame-pointer"); + c_file->args.append("-fno-unwind-tables"); + c_file->args.append("-fno-asynchronous-unwind-tables"); + c_file->args.append("-ffunction-sections"); + c_file->args.append("-fdata-sections"); +} + +static const char *musl_arch_names[] = { + "aarch64", + "arm", + "generic", + "i386", + "m68k", + "microblaze", + "mips", + "mips64", + "mipsn32", + "or1k", + "powerpc", + "powerpc64", + "s390x", + "sh", + "x32", + "x86_64", +}; + +static bool is_musl_arch_name(const char *name) { + for (size_t i = 0; i < array_length(musl_arch_names); i += 1) { + if (strcmp(name, musl_arch_names[i]) == 0) + return true; + } + return false; +} + +static const char *build_musl(CodeGen *parent) { + CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); + codegen_set_out_name(child_gen, buf_create_from_str("c")); + child_gen->is_static = true; + + // When there is a src/<arch>/foo.* then it should substitute for src/foo.* + // Even a .s file can substitute for a .c file. + + enum MuslSrc { + MuslSrcAsm, + MuslSrcNormal, + MuslSrcO3, + }; + + const char *target_musl_arch_name = musl_arch_name(parent->zig_target); + + HashMap<Buf *, MuslSrc, buf_hash, buf_eql_buf> source_table = {}; + source_table.init(1800); + + for (size_t i = 0; i < array_length(ZIG_MUSL_SRC_FILES); i += 1) { + Buf *src_file = buf_create_from_str(ZIG_MUSL_SRC_FILES[i]); + + MuslSrc src_kind; + if (buf_ends_with_str(src_file, ".c")) { + assert(buf_starts_with_str(src_file, "musl/src/")); + bool want_O3 = buf_starts_with_str(src_file, "musl/src/malloc/") || + buf_starts_with_str(src_file, "musl/src/string/") || + buf_starts_with_str(src_file, "musl/src/internal/"); + src_kind = want_O3 ? MuslSrcO3 : MuslSrcNormal; + } else if (buf_ends_with_str(src_file, ".s") || buf_ends_with_str(src_file, ".S")) { + src_kind = MuslSrcAsm; + } else { + continue; + } + if (ZIG_OS_SEP_CHAR != '/') { + buf_replace(src_file, '/', ZIG_OS_SEP_CHAR); + } + source_table.put_unique(src_file, src_kind); + } + + ZigList<CFile *> c_source_files = {0}; + + Buf dirname = BUF_INIT; + Buf basename = BUF_INIT; + Buf noextbasename = BUF_INIT; + Buf dirbasename = BUF_INIT; + Buf before_arch_dir = BUF_INIT; + Buf override_c = BUF_INIT; + Buf override_s = BUF_INIT; + Buf override_S = BUF_INIT; + + auto source_it = source_table.entry_iterator(); + for (;;) { + auto *entry = source_it.next(); + if (!entry) break; + + Buf *src_file = entry->key; + MuslSrc src_kind = entry->value; + + os_path_split(src_file, &dirname, &basename); + os_path_extname(&basename, &noextbasename, nullptr); + os_path_split(&dirname, &before_arch_dir, &dirbasename); + if (is_musl_arch_name(buf_ptr(&dirbasename))) { + // We find these by explicitly looking for overrides. + continue; + } + // Look for an arch specific override. + buf_resize(&override_c, 0); + buf_resize(&override_s, 0); + buf_resize(&override_S, 0); + + buf_appendf(&override_c, "%s" OS_SEP "%s" OS_SEP "%s.c", + buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename)); + buf_appendf(&override_s, "%s" OS_SEP "%s" OS_SEP "%s.s", + buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename)); + buf_appendf(&override_S, "%s" OS_SEP "%s" OS_SEP "%s.S", + buf_ptr(&dirname), target_musl_arch_name, buf_ptr(&noextbasename)); + + if (source_table.maybe_get(&override_c) != nullptr) { + src_file = &override_c; + src_kind = (src_kind == MuslSrcAsm) ? MuslSrcNormal : src_kind; + } else if (source_table.maybe_get(&override_s) != nullptr) { + src_file = &override_s; + src_kind = MuslSrcAsm; + } else if (source_table.maybe_get(&override_S) != nullptr) { + src_file = &override_S; + src_kind = MuslSrcAsm; + } + + Buf *full_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "%s", + buf_ptr(parent->zig_lib_dir), buf_ptr(src_file)); + + if (src_kind == MuslSrcAsm) { + codegen_add_assembly(child_gen, full_path); + } else { + CFile *c_file = allocate<CFile>(1); + c_file->source_path = buf_ptr(full_path); + musl_add_cc_args(parent, c_file); + c_file->args.append("-Wno-ignored-attributes"); + c_file->args.append("-Wno-bitwise-op-parentheses"); + c_file->args.append("-Wno-logical-op-parentheses"); + c_file->args.append("-Wno-dangling-else"); + c_file->args.append("-Wno-shift-op-parentheses"); + c_file->args.append("-Qunused-arguments"); + c_file->args.append("-Wno-unknown-pragmas"); + c_file->args.append("-Wno-string-plus-int"); + c_file->args.append("-Wno-parentheses"); + if (src_kind == MuslSrcO3) { + c_file->args.append("-O3"); + } + c_source_files.append(c_file); + } + } + + child_gen->c_source_files = c_source_files; + codegen_build_and_link(child_gen); + return buf_ptr(&child_gen->output_file_path); +} + + static const char *get_libc_crt_file(CodeGen *parent, const char *file) { if (parent->libc == nullptr && target_is_glibc(parent)) { if (strcmp(file, "crti.o") == 0) { @@ -516,6 +755,29 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { } else { zig_unreachable(); } + } else if (parent->libc == nullptr && target_is_musl(parent)) { + if (strcmp(file, "crti.o") == 0) { + return build_asm_object(parent, "crti", musl_start_asm_path(parent, "crti.s")); + } else if (strcmp(file, "crtn.o") == 0) { + return build_asm_object(parent, "crtn", musl_start_asm_path(parent, "crtn.s")); + } else if (strcmp(file, "crt1.o") == 0) { + CFile *c_file = allocate<CFile>(1); + c_file->source_path = path_from_libc(parent, "musl" OS_SEP "crt" OS_SEP "crt1.c"); + musl_add_cc_args(parent, c_file); + c_file->args.append("-fno-stack-protector"); + c_file->args.append("-DCRT"); + return build_libc_object(parent, "crt1", c_file); + } else if (strcmp(file, "Scrt1.o") == 0) { + CFile *c_file = allocate<CFile>(1); + c_file->source_path = path_from_libc(parent, "musl" OS_SEP "crt" OS_SEP "Scrt1.c"); + musl_add_cc_args(parent, c_file); + c_file->args.append("-fPIC"); + c_file->args.append("-fno-stack-protector"); + c_file->args.append("-DCRT"); + return build_libc_object(parent, "Scrt1", c_file); + } else { + zig_unreachable(); + } } else { assert(parent->libc != nullptr); Buf *out_buf = buf_alloc(); @@ -768,7 +1030,7 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc is linked specially continue; } - if (g->libc == nullptr && target_is_glibc(g)) { + if (g->libc == nullptr && (target_is_glibc(g) || target_is_musl(g))) { // these libraries are always linked below when targeting glibc if (buf_eql_str(link_lib->name, "m")) { continue; @@ -794,24 +1056,26 @@ static void construct_linker_job_elf(LinkJob *lj) { // libc dep if (g->libc_link_lib != nullptr) { - if (g->is_static) { - lj->args.append("--start-group"); - lj->args.append("-lgcc"); - lj->args.append("-lgcc_eh"); - lj->args.append("-lc"); - lj->args.append("-lm"); - lj->args.append("--end-group"); - } else if (g->libc != nullptr) { - lj->args.append("-lgcc"); - lj->args.append("--as-needed"); - lj->args.append("-lgcc_s"); - lj->args.append("--no-as-needed"); - lj->args.append("-lc"); - lj->args.append("-lm"); - lj->args.append("-lgcc"); - lj->args.append("--as-needed"); - lj->args.append("-lgcc_s"); - lj->args.append("--no-as-needed"); + if (g->libc != nullptr) { + if (g->is_static) { + lj->args.append("--start-group"); + lj->args.append("-lgcc"); + lj->args.append("-lgcc_eh"); + lj->args.append("-lc"); + lj->args.append("-lm"); + lj->args.append("--end-group"); + } else { + lj->args.append("-lgcc"); + lj->args.append("--as-needed"); + lj->args.append("-lgcc_s"); + lj->args.append("--no-as-needed"); + lj->args.append("-lc"); + lj->args.append("-lm"); + lj->args.append("-lgcc"); + lj->args.append("--as-needed"); + lj->args.append("-lgcc_s"); + lj->args.append("--no-as-needed"); + } } else if (target_is_glibc(g)) { lj->args.append(build_libunwind(g)); lj->args.append(build_dummy_so(g, "c", 6)); @@ -820,6 +1084,9 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append(build_dummy_so(g, "dl", 2)); lj->args.append(build_dummy_so(g, "rt", 1)); lj->args.append(get_libc_crt_file(g, "libc_nonshared.a")); + } else if (target_is_musl(g)) { + lj->args.append(build_libunwind(g)); + lj->args.append(build_musl(g)); } else { zig_unreachable(); } |
