self-host dynamic linker detection

This commit is contained in:
Andrew Kelley 2020-02-17 15:23:59 -05:00
parent c784c52819
commit 2f9c5c0644
No known key found for this signature in database
GPG Key ID: 7C5F548F728501A9
17 changed files with 430 additions and 532 deletions

View File

@ -2974,18 +2974,26 @@ pub fn nanosleep(seconds: u64, nanoseconds: u64) void {
}
pub fn dl_iterate_phdr(
comptime T: type,
callback: extern fn (info: *dl_phdr_info, size: usize, data: ?*T) i32,
data: ?*T,
) isize {
context: var,
comptime Error: type,
comptime callback: fn (info: *dl_phdr_info, size: usize, context: @TypeOf(context)) Error!void,
) Error!void {
const Context = @TypeOf(context);
if (builtin.object_format != .elf)
@compileError("dl_iterate_phdr is not available for this target");
if (builtin.link_libc) {
return system.dl_iterate_phdr(
@ptrCast(std.c.dl_iterate_phdr_callback, callback),
@ptrCast(?*c_void, data),
);
switch (system.dl_iterate_phdr(struct {
fn callbackC(info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int {
const context_ptr = @ptrCast(*const Context, @alignCast(@alignOf(*const Context), data));
callback(info, size, context_ptr.*) catch |err| return @errorToInt(err);
return 0;
}
}.callbackC, @intToPtr(?*c_void, @ptrToInt(&context)))) {
0 => return,
else => |err| return @errSetCast(Error, @intToError(@intCast(u16, err))), // TODO don't hardcode u16
}
}
const elf_base = std.process.getBaseAddress();
@ -3007,11 +3015,10 @@ pub fn dl_iterate_phdr(
.dlpi_phnum = ehdr.e_phnum,
};
return callback(&info, @sizeOf(dl_phdr_info), data);
return callback(&info, @sizeOf(dl_phdr_info), context);
}
// Last return value from the callback function
var last_r: isize = 0;
while (it.next()) |entry| {
var dlpi_phdr: [*]elf.Phdr = undefined;
var dlpi_phnum: u16 = undefined;
@ -3033,11 +3040,8 @@ pub fn dl_iterate_phdr(
.dlpi_phnum = dlpi_phnum,
};
last_r = callback(&info, @sizeOf(dl_phdr_info), data);
if (last_r != 0) break;
try callback(&info, @sizeOf(dl_phdr_info), context);
}
return last_r;
}
pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError;

View File

@ -613,3 +613,59 @@ pub fn getBaseAddress() usize {
else => @compileError("Unsupported OS"),
}
}
/// Caller owns the result value and each inner slice.
pub fn getSelfExeSharedLibPaths(allocator: *Allocator) error{OutOfMemory}![][:0]u8 {
switch (builtin.link_mode) {
.Static => return &[_][:0]u8{},
.Dynamic => {},
}
const List = std.ArrayList([:0]u8);
switch (builtin.os) {
.linux,
.freebsd,
.netbsd,
.dragonfly,
=> {
var paths = List.init(allocator);
errdefer {
const slice = paths.toOwnedSlice();
for (slice) |item| {
allocator.free(item);
}
allocator.free(slice);
}
try os.dl_iterate_phdr(&paths, error{OutOfMemory}, struct {
fn callback(info: *os.dl_phdr_info, size: usize, list: *List) !void {
const name = info.dlpi_name orelse return;
if (name[0] == '/') {
const item = try mem.dupeZ(list.allocator, u8, mem.toSliceConst(u8, name));
errdefer list.allocator.free(item);
try list.append(item);
}
}
}.callback);
return paths.toOwnedSlice();
},
.macosx, .ios, .watchos, .tvos => {
var paths = List.init(allocator);
errdefer {
const slice = paths.toOwnedSlice();
for (slice) |item| {
allocator.free(item);
}
allocator.free(slice);
}
const img_count = std.c._dyld_image_count();
var i: u32 = 0;
while (i < img_count) : (i += 1) {
const name = std.c._dyld_get_image_name(i);
const item = try mem.dupeZ(allocator, u8, mem.toSliceConst(u8, name));
errdefer allocator.free(item);
try paths.append(item);
}
return paths.toOwnedSlice();
},
else => return error.UnimplementedSelfExeSharedPaths,
}
}

View File

@ -1037,6 +1037,13 @@ pub const Target = union(enum) {
};
}
pub fn isAndroid(self: Target) bool {
return switch (self.getAbi()) {
.android => true,
else => false,
};
}
pub fn isDragonFlyBSD(self: Target) bool {
return switch (self.getOs()) {
.dragonfly => true,
@ -1196,6 +1203,136 @@ pub const Target = union(enum) {
return .unavailable;
}
pub const FloatAbi = enum {
hard,
soft,
soft_fp,
};
pub fn getFloatAbi(self: Target) FloatAbi {
return switch (self.getAbi()) {
.gnueabihf,
.eabihf,
.musleabihf,
=> .hard,
else => .soft,
};
}
/// Caller owns returned memory.
pub fn getStandardDynamicLinkerPath(
self: Target,
allocator: *mem.Allocator,
) error{
OutOfMemory,
UnknownDynamicLinkerPath,
}![:0]u8 {
const a = allocator;
if (self.isAndroid()) {
return mem.dupeZ(a, u8, if (self.getArchPtrBitWidth() == 64)
"/system/bin/linker64"
else
"/system/bin/linker");
}
if (self.isMusl()) {
var result = try std.Buffer.init(allocator, "/lib/ld-musl-");
defer result.deinit();
var is_arm = false;
switch (self.getArch()) {
.arm, .thumb => {
try result.append("arm");
is_arm = true;
},
.armeb, .thumbeb => {
try result.append("armeb");
is_arm = true;
},
else => |arch| try result.append(@tagName(arch)),
}
if (is_arm and self.getFloatAbi() == .hard) {
try result.append("hf");
}
try result.append(".so.1");
return result.toOwnedSlice();
}
switch (self.getOs()) {
.freebsd => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.1"),
.netbsd => return mem.dupeZ(a, u8, "/libexec/ld.elf_so"),
.dragonfly => return mem.dupeZ(a, u8, "/libexec/ld-elf.so.2"),
.linux => switch (self.getArch()) {
.i386,
.sparc,
.sparcel,
=> return mem.dupeZ(a, u8, "/lib/ld-linux.so.2"),
.aarch64 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64.so.1"),
.aarch64_be => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_be.so.1"),
.aarch64_32 => return mem.dupeZ(a, u8, "/lib/ld-linux-aarch64_32.so.1"),
.arm,
.armeb,
.thumb,
.thumbeb,
=> return mem.dupeZ(a, u8, switch (self.getFloatAbi()) {
.hard => "/lib/ld-linux-armhf.so.3",
else => "/lib/ld-linux.so.3",
}),
.mips,
.mipsel,
.mips64,
.mips64el,
=> return error.UnknownDynamicLinkerPath,
.powerpc => return mem.dupeZ(a, u8, "/lib/ld.so.1"),
.powerpc64, .powerpc64le => return mem.dupeZ(a, u8, "/lib64/ld64.so.2"),
.s390x => return mem.dupeZ(a, u8, "/lib64/ld64.so.1"),
.sparcv9 => return mem.dupeZ(a, u8, "/lib64/ld-linux.so.2"),
.x86_64 => return mem.dupeZ(a, u8, switch (self.getAbi()) {
.gnux32 => "/libx32/ld-linux-x32.so.2",
else => "/lib64/ld-linux-x86-64.so.2",
}),
.riscv32 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv32-ilp32.so.1"),
.riscv64 => return mem.dupeZ(a, u8, "/lib/ld-linux-riscv64-lp64.so.1"),
.arc,
.avr,
.bpfel,
.bpfeb,
.hexagon,
.msp430,
.r600,
.amdgcn,
.tce,
.tcele,
.xcore,
.nvptx,
.nvptx64,
.le32,
.le64,
.amdil,
.amdil64,
.hsail,
.hsail64,
.spir,
.spir64,
.kalimba,
.shave,
.lanai,
.wasm32,
.wasm64,
.renderscript32,
.renderscript64,
=> return error.UnknownDynamicLinkerPath,
},
else => return error.UnknownDynamicLinkerPath,
}
}
};
test "parseCpuFeatureSet" {

View File

@ -6,6 +6,14 @@ const fs = std.fs;
const warn = std.debug.warn;
pub fn detectDynamicLinker(allocator: *mem.Allocator, target: std.Target) ![:0]u8 {
if (target == .Native) {
return @import("libc_installation.zig").detectNativeDynamicLinker(allocator);
} else {
return target.getStandardDynamicLinkerPath(allocator);
}
}
/// Caller must free result
pub fn testZigInstallPrefix(allocator: *mem.Allocator, test_path: []const u8) ![]u8 {
const test_zig_dir = try fs.path.join(allocator, &[_][]const u8{ test_path, "lib", "zig" });

View File

@ -492,7 +492,7 @@ pub const LibCInstallation = struct {
const default_cc_exe = if (is_windows) "cc.exe" else "cc";
/// caller owns returned memory
pub fn ccPrintFileName(
fn ccPrintFileName(
allocator: *Allocator,
o_file: []const u8,
want_dirname: enum { full_path, only_dir },
@ -535,6 +535,43 @@ pub fn ccPrintFileName(
}
}
/// Caller owns returned memory.
pub fn detectNativeDynamicLinker(allocator: *Allocator) ![:0]u8 {
const standard_ld_path = try std.Target.current.getStandardDynamicLinkerPath(allocator);
var standard_ld_path_resource: ?[:0]u8 = standard_ld_path; // Set to null to avoid freeing it.
defer if (standard_ld_path_resource) |s| allocator.free(s);
const standard_ld_basename = fs.path.basename(standard_ld_path);
{
// Best case scenario: the current executable is dynamically linked, and we can iterate
// over our own shared objects and find a dynamic linker.
const lib_paths = try std.process.getSelfExeSharedLibPaths(allocator);
defer allocator.free(lib_paths);
for (lib_paths) |lib_path| {
if (std.mem.endsWith(u8, lib_path, standard_ld_basename)) {
return std.mem.dupeZ(allocator, u8, lib_path);
}
}
}
// If Zig is statically linked, such as via distributed binary static builds, the above
// trick won't work. What are we left with? Try to run the system C compiler and get
// it to tell us the dynamic linker path.
return ccPrintFileName(allocator, standard_ld_basename, .full_path) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.LibCRuntimeNotFound,
error.CCompilerExitCode,
error.CCompilerCrashed,
error.UnableToSpawnCCompiler,
=> {
standard_ld_path_resource = null; // Prevent freeing standard_ld_path.
return standard_ld_path;
},
};
}
const Search = struct {
path: []const u8,
version: []const u8,

View File

@ -109,6 +109,7 @@ const Error = extern enum {
LibCKernel32LibNotFound,
UnsupportedArchitecture,
WindowsSdkNotFound,
UnknownDynamicLinkerPath,
};
const FILE = std.c.FILE;
@ -1012,24 +1013,100 @@ export fn stage2_libc_render(stage1_libc: *Stage2LibCInstallation, output_file:
}
// ABI warning
export fn stage2_libc_cc_print_file_name(
out_ptr: *[*:0]u8,
out_len: *usize,
o_file: [*:0]const u8,
want_dirname: bool,
) Error {
const result = @import("libc_installation.zig").ccPrintFileName(
const Stage2Target = extern struct {
arch: c_int,
sub_arch: c_int,
vendor: c_int,
os: c_int,
abi: c_int,
glibc_version: ?*Stage2GLibCVersion, // null means default
cpu_features: *Stage2CpuFeatures,
is_native: bool,
};
// ABI warning
const Stage2GLibCVersion = extern struct {
major: u32,
minor: u32,
patch: u32,
};
// ABI warning
export fn stage2_detect_dynamic_linker(in_target: *const Stage2Target, out_ptr: *[*:0]u8, out_len: *usize) Error {
const target: Target = if (in_target.is_native) .Native else .{
.Cross = .{
.arch = switch (enumInt(@TagType(Target.Arch), in_target.arch)) {
.arm => .{ .arm = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
.armeb => .{ .armeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
.thumb => .{ .thumb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
.thumbeb => .{ .thumbeb = enumInt(Target.Arch.Arm32, in_target.sub_arch) },
.aarch64 => .{ .aarch64 = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
.aarch64_be => .{ .aarch64_be = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
.aarch64_32 => .{ .aarch64_32 = enumInt(Target.Arch.Arm64, in_target.sub_arch) },
.kalimba => .{ .kalimba = enumInt(Target.Arch.Kalimba, in_target.sub_arch) },
.arc => .arc,
.avr => .avr,
.bpfel => .bpfel,
.bpfeb => .bpfeb,
.hexagon => .hexagon,
.mips => .mips,
.mipsel => .mipsel,
.mips64 => .mips64,
.mips64el => .mips64el,
.msp430 => .msp430,
.powerpc => .powerpc,
.powerpc64 => .powerpc64,
.powerpc64le => .powerpc64le,
.r600 => .r600,
.amdgcn => .amdgcn,
.riscv32 => .riscv32,
.riscv64 => .riscv64,
.sparc => .sparc,
.sparcv9 => .sparcv9,
.sparcel => .sparcel,
.s390x => .s390x,
.tce => .tce,
.tcele => .tcele,
.i386 => .i386,
.x86_64 => .x86_64,
.xcore => .xcore,
.nvptx => .nvptx,
.nvptx64 => .nvptx64,
.le32 => .le32,
.le64 => .le64,
.amdil => .amdil,
.amdil64 => .amdil64,
.hsail => .hsail,
.hsail64 => .hsail64,
.spir => .spir,
.spir64 => .spir64,
.shave => .shave,
.lanai => .lanai,
.wasm32 => .wasm32,
.wasm64 => .wasm64,
.renderscript32 => .renderscript32,
.renderscript64 => .renderscript64,
},
.os = enumInt(Target.Os, in_target.os),
.abi = enumInt(Target.Abi, in_target.abi),
.cpu_features = in_target.cpu_features.cpu_features,
},
};
const result = @import("introspect.zig").detectDynamicLinker(
std.heap.c_allocator,
mem.toSliceConst(u8, o_file),
if (want_dirname) .only_dir else .full_path,
target,
) catch |err| switch (err) {
error.OutOfMemory => return .OutOfMemory,
error.LibCRuntimeNotFound => return .FileNotFound,
error.CCompilerExitCode => return .CCompilerExitCode,
error.CCompilerCrashed => return .CCompilerCrashed,
error.UnableToSpawnCCompiler => return .UnableToSpawnCCompiler,
error.UnknownDynamicLinkerPath => return .UnknownDynamicLinkerPath,
};
out_ptr.* = result.ptr;
out_len.* = result.len;
return .None;
}
fn enumInt(comptime Enum: type, int: c_int) Enum {
return @intToEnum(Enum, @intCast(@TagType(Enum), int));
}

View File

@ -2,143 +2,6 @@ const std = @import("std");
const Target = std.Target;
const llvm = @import("llvm.zig");
pub const FloatAbi = enum {
Hard,
Soft,
SoftFp,
};
/// TODO expose the arch and subarch separately
pub fn isArmOrThumb(self: Target) bool {
return switch (self.getArch()) {
.arm,
.armeb,
.aarch64,
.aarch64_be,
.thumb,
.thumbeb,
=> true,
else => false,
};
}
pub fn getFloatAbi(self: Target) FloatAbi {
return switch (self.getAbi()) {
.gnueabihf,
.eabihf,
.musleabihf,
=> .Hard,
else => .Soft,
};
}
pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
const env = self.getAbi();
const arch = self.getArch();
const os = self.getOs();
switch (os) {
.freebsd => {
return "/libexec/ld-elf.so.1";
},
.linux => {
switch (env) {
.android => {
if (self.getArchPtrBitWidth() == 64) {
return "/system/bin/linker64";
} else {
return "/system/bin/linker";
}
},
.gnux32 => {
if (arch == .x86_64) {
return "/libx32/ld-linux-x32.so.2";
}
},
.musl,
.musleabi,
.musleabihf,
=> {
if (arch == .x86_64) {
return "/lib/ld-musl-x86_64.so.1";
}
},
else => {},
}
switch (arch) {
.i386,
.sparc,
.sparcel,
=> return "/lib/ld-linux.so.2",
.aarch64 => return "/lib/ld-linux-aarch64.so.1",
.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
.arm,
.thumb,
=> return switch (getFloatAbi(self)) {
.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
.armeb,
.thumbeb,
=> return switch (getFloatAbi(self)) {
.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
.mips,
.mipsel,
.mips64,
.mips64el,
=> return null,
.powerpc => return "/lib/ld.so.1",
.powerpc64 => return "/lib64/ld64.so.2",
.powerpc64le => return "/lib64/ld64.so.2",
.s390x => return "/lib64/ld64.so.1",
.sparcv9 => return "/lib64/ld-linux.so.2",
.x86_64 => return "/lib64/ld-linux-x86-64.so.2",
.arc,
.avr,
.bpfel,
.bpfeb,
.hexagon,
.msp430,
.r600,
.amdgcn,
.riscv32,
.riscv64,
.tce,
.tcele,
.xcore,
.nvptx,
.nvptx64,
.le32,
.le64,
.amdil,
.amdil64,
.hsail,
.hsail64,
.spir,
.spir64,
.kalimba,
.shave,
.lanai,
.wasm32,
.wasm64,
.renderscript32,
.renderscript64,
.aarch64_32,
=> return null,
}
},
else => return null,
}
}
pub fn getDarwinArchString(self: Target) [:0]const u8 {
const arch = self.getArch();
switch (arch) {

View File

@ -8624,7 +8624,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
break;
}
buf_appendf(contents, "pub const output_mode = OutputMode.%s;\n", out_type);
const char *link_type = g->is_dynamic ? "Dynamic" : "Static";
const char *link_type = g->have_dynamic_link ? "Dynamic" : "Static";
buf_appendf(contents, "pub const link_mode = LinkMode.%s;\n", link_type);
buf_appendf(contents, "pub const is_test = %s;\n", bool_to_str(g->is_test_build));
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
@ -8731,7 +8731,7 @@ static Error define_builtin_compile_vars(CodeGen *g) {
cache_int(&cache_hash, g->build_mode);
cache_bool(&cache_hash, g->strip_debug_symbols);
cache_int(&cache_hash, g->out_type);
cache_bool(&cache_hash, g->is_dynamic);
cache_bool(&cache_hash, detect_dynamic_link(g));
cache_bool(&cache_hash, g->is_test_build);
cache_bool(&cache_hash, g->is_single_threaded);
cache_bool(&cache_hash, g->test_is_evented);
@ -8957,6 +8957,8 @@ static void init(CodeGen *g) {
}
static void detect_dynamic_linker(CodeGen *g) {
Error err;
if (g->dynamic_linker_path != nullptr)
return;
if (!g->have_dynamic_link)
@ -8964,45 +8966,15 @@ static void detect_dynamic_linker(CodeGen *g) {
if (g->out_type == OutTypeObj || (g->out_type == OutTypeLib && !g->is_dynamic))
return;
const char *standard_ld_path = target_dynamic_linker(g->zig_target);
if (standard_ld_path == nullptr)
return;
if (g->zig_target->is_native) {
// target_dynamic_linker is usually correct. However on some systems, such as NixOS
// it will be incorrect. See if we can do better by looking at what zig's own
// dynamic linker path is.
g->dynamic_linker_path = get_self_dynamic_linker_path();
if (g->dynamic_linker_path != nullptr)
return;
// If Zig is statically linked, such as via distributed binary static builds, the above
// trick won't work. What are we left with? Try to run the system C compiler and get
// it to tell us the dynamic linker path
#if defined(ZIG_OS_LINUX)
{
Error err;
for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
const char *lib_name = possible_ld_names[i];
char *result_ptr;
size_t result_len;
if ((err = stage2_libc_cc_print_file_name(&result_ptr, &result_len, lib_name, false))) {
if (err != ErrorCCompilerCannotFindFile && err != ErrorNoCCompilerInstalled) {
fprintf(stderr, "Unable to detect native dynamic linker: %s\n", err_str(err));
exit(1);
}
continue;
}
g->dynamic_linker_path = buf_create_from_mem(result_ptr, result_len);
// Skips heap::c_allocator because the memory is allocated by stage2 library.
free(result_ptr);
return;
}
}
#endif
char *dynamic_linker_ptr;
size_t dynamic_linker_len;
if ((err = stage2_detect_dynamic_linker(g->zig_target, &dynamic_linker_ptr, &dynamic_linker_len))) {
fprintf(stderr, "Unable to detect dynamic linker: %s\n", err_str(err));
exit(1);
}
g->dynamic_linker_path = buf_create_from_str(standard_ld_path);
g->dynamic_linker_path = buf_create_from_mem(dynamic_linker_ptr, dynamic_linker_len);
// Skips heap::c_allocator because the memory is allocated by stage2 library.
free(dynamic_linker_ptr);
}
static void detect_libc(CodeGen *g) {

View File

@ -4,20 +4,6 @@
#include <stdio.h>
static Buf saved_dynamic_linker_path = BUF_INIT;
static bool searched_for_dyn_linker = false;
static void detect_dynamic_linker(Buf *lib_path) {
#if defined(ZIG_OS_LINUX)
for (size_t i = 0; possible_ld_names[i] != NULL; i += 1) {
if (buf_ends_with_str(lib_path, possible_ld_names[i])) {
buf_init_from_buf(&saved_dynamic_linker_path, lib_path);
break;
}
}
#endif
}
Buf *get_self_libc_path(void) {
static Buf saved_libc_path = BUF_INIT;
static bool searched_for_libc = false;
@ -43,25 +29,6 @@ Buf *get_self_libc_path(void) {
}
}
Buf *get_self_dynamic_linker_path(void) {
for (;;) {
if (saved_dynamic_linker_path.list.length != 0) {
return &saved_dynamic_linker_path;
}
if (searched_for_dyn_linker)
return nullptr;
ZigList<Buf *> lib_paths = {};
Error err;
if ((err = os_self_exe_shared_libs(lib_paths)))
return nullptr;
for (size_t i = 0; i < lib_paths.length; i += 1) {
Buf *lib_path = lib_paths.at(i);
detect_dynamic_linker(lib_path);
}
searched_for_dyn_linker = true;
}
}
Error get_compiler_id(Buf **result) {
static Buf saved_compiler_id = BUF_INIT;
@ -98,7 +65,6 @@ Error get_compiler_id(Buf **result) {
return err;
for (size_t i = 0; i < lib_paths.length; i += 1) {
Buf *lib_path = lib_paths.at(i);
detect_dynamic_linker(lib_path);
if ((err = cache_add_file(ch, lib_path)))
return err;
}

View File

@ -12,7 +12,6 @@
#include "error.hpp"
Error get_compiler_id(Buf **result);
Buf *get_self_dynamic_linker_path(void);
Buf *get_self_libc_path(void);
Buf *get_zig_lib_dir(void);

View File

@ -80,6 +80,7 @@ const char *err_str(Error err) {
case ErrorLibCKernel32LibNotFound: return "kernel32 library not found";
case ErrorUnsupportedArchitecture: return "unsupported architecture";
case ErrorWindowsSdkNotFound: return "Windows SDK not found";
case ErrorUnknownDynamicLinkerPath: return "Windows SDK not found";
}
return "(invalid error)";
}

View File

@ -2129,21 +2129,3 @@ void os_file_close(OsFile *file) {
*file = -1;
#endif
}
#ifdef ZIG_OS_LINUX
const char *possible_ld_names[] = {
#if defined(ZIG_ARCH_X86_64)
"ld-linux-x86-64.so.2",
"ld-musl-x86_64.so.1",
#elif defined(ZIG_ARCH_ARM64)
"ld-linux-aarch64.so.1",
"ld-musl-aarch64.so.1",
#elif defined(ZIG_ARCH_ARM)
"ld-linux-armhf.so.3",
"ld-musl-armhf.so.1",
"ld-linux.so.3",
"ld-musl-arm.so.1",
#endif
NULL,
};
#endif

View File

@ -43,10 +43,6 @@
#define ZIG_ARCH_UNKNOWN
#endif
#ifdef ZIG_OS_LINUX
extern const char *possible_ld_names[];
#endif
#if defined(ZIG_OS_WINDOWS)
#define ZIG_PRI_usize "I64u"
#define ZIG_PRI_i64 "I64d"

View File

@ -171,9 +171,7 @@ enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc) {
stage2_panic(msg, strlen(msg));
}
enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len,
const char *o_file, bool want_dirname)
{
const char *msg = "stage0 called stage2_libc_cc_print_file_name";
enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target, char **out_ptr, size_t *out_len) {
const char *msg = "stage0 called stage2_detect_dynamic_linker";
stage2_panic(msg, strlen(msg));
}

View File

@ -12,6 +12,8 @@
#include <stdint.h>
#include <stdio.h>
#include "zig_llvm.h"
#ifdef __cplusplus
#define ZIG_EXTERN_C extern "C"
#else
@ -100,6 +102,7 @@ enum Error {
ErrorLibCKernel32LibNotFound,
ErrorUnsupportedArchitecture,
ErrorWindowsSdkNotFound,
ErrorUnknownDynamicLinkerPath,
};
// ABI warning
@ -242,8 +245,70 @@ ZIG_EXTERN_C enum Error stage2_libc_parse(struct Stage2LibCInstallation *libc, c
ZIG_EXTERN_C enum Error stage2_libc_render(struct Stage2LibCInstallation *self, FILE *file);
// ABI warning
ZIG_EXTERN_C enum Error stage2_libc_find_native(struct Stage2LibCInstallation *libc);
// ABI warning
ZIG_EXTERN_C enum Error stage2_libc_cc_print_file_name(char **out_ptr, size_t *out_len,
const char *o_file, bool want_dirname);
// Synchronize with target.cpp::os_list
enum Os {
OsFreestanding,
OsAnanas,
OsCloudABI,
OsDragonFly,
OsFreeBSD,
OsFuchsia,
OsIOS,
OsKFreeBSD,
OsLinux,
OsLv2, // PS3
OsMacOSX,
OsNetBSD,
OsOpenBSD,
OsSolaris,
OsWindows,
OsHaiku,
OsMinix,
OsRTEMS,
OsNaCl, // Native Client
OsCNK, // BG/P Compute-Node Kernel
OsAIX,
OsCUDA, // NVIDIA CUDA
OsNVCL, // NVIDIA OpenCL
OsAMDHSA, // AMD HSA Runtime
OsPS4,
OsELFIAMCU,
OsTvOS, // Apple tvOS
OsWatchOS, // Apple watchOS
OsMesa3D,
OsContiki,
OsAMDPAL,
OsHermitCore,
OsHurd,
OsWASI,
OsEmscripten,
OsUefi,
OsOther,
};
// ABI warning
struct ZigGLibCVersion {
uint32_t major; // always 2
uint32_t minor;
uint32_t patch;
};
// ABI warning
struct ZigTarget {
enum ZigLLVM_ArchType arch;
enum ZigLLVM_SubArchType sub_arch;
enum ZigLLVM_VendorType vendor;
Os os;
enum ZigLLVM_EnvironmentType abi;
struct ZigGLibCVersion *glibc_version; // null means default
struct Stage2CpuFeatures *cpu_features;
bool is_native;
};
// ABI warning
ZIG_EXTERN_C enum Error stage2_detect_dynamic_linker(const struct ZigTarget *target,
char **out_ptr, size_t *out_len);
#endif

View File

@ -1204,213 +1204,10 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
}
}
enum FloatAbi {
FloatAbiHard,
FloatAbiSoft,
FloatAbiSoftFp,
};
static FloatAbi get_float_abi(const ZigTarget *target) {
const ZigLLVM_EnvironmentType env = target->abi;
if (env == ZigLLVM_GNUEABIHF ||
env == ZigLLVM_EABIHF ||
env == ZigLLVM_MuslEABIHF)
{
return FloatAbiHard;
} else {
return FloatAbiSoft;
}
}
static bool is_64_bit(ZigLLVM_ArchType arch) {
return target_arch_pointer_bit_width(arch) == 64;
}
bool target_is_android(const ZigTarget *target) {
return target->abi == ZigLLVM_Android;
}
const char *target_dynamic_linker(const ZigTarget *target) {
if (target_is_android(target)) {
return is_64_bit(target->arch) ? "/system/bin/linker64" : "/system/bin/linker";
}
if (target_is_musl(target)) {
Buf buf = BUF_INIT;
buf_init_from_str(&buf, "/lib/ld-musl-");
bool is_arm = false;
switch (target->arch) {
case ZigLLVM_arm:
case ZigLLVM_thumb:
buf_append_str(&buf, "arm");
is_arm = true;
break;
case ZigLLVM_armeb:
case ZigLLVM_thumbeb:
buf_append_str(&buf, "armeb");
is_arm = true;
break;
default:
buf_append_str(&buf, target_arch_name(target->arch));
}
if (is_arm && get_float_abi(target) == FloatAbiHard) {
buf_append_str(&buf, "hf");
}
buf_append_str(&buf, ".so.1");
return buf_ptr(&buf);
}
switch (target->os) {
case OsFreeBSD:
return "/libexec/ld-elf.so.1";
case OsNetBSD:
return "/libexec/ld.elf_so";
case OsDragonFly:
return "/libexec/ld-elf.so.2";
case OsLinux: {
const ZigLLVM_EnvironmentType abi = target->abi;
switch (target->arch) {
case ZigLLVM_UnknownArch:
zig_unreachable();
case ZigLLVM_x86:
case ZigLLVM_sparc:
case ZigLLVM_sparcel:
return "/lib/ld-linux.so.2";
case ZigLLVM_aarch64:
return "/lib/ld-linux-aarch64.so.1";
case ZigLLVM_aarch64_be:
return "/lib/ld-linux-aarch64_be.so.1";
case ZigLLVM_aarch64_32:
return "/lib/ld-linux-aarch64_32.so.1";
case ZigLLVM_arm:
case ZigLLVM_thumb:
if (get_float_abi(target) == FloatAbiHard) {
return "/lib/ld-linux-armhf.so.3";
} else {
return "/lib/ld-linux.so.3";
}
case ZigLLVM_armeb:
case ZigLLVM_thumbeb:
if (get_float_abi(target) == FloatAbiHard) {
return "/lib/ld-linux-armhf.so.3";
} else {
return "/lib/ld-linux.so.3";
}
case ZigLLVM_mips:
case ZigLLVM_mipsel:
case ZigLLVM_mips64:
case ZigLLVM_mips64el:
zig_panic("TODO implement target_dynamic_linker for mips");
case ZigLLVM_ppc:
return "/lib/ld.so.1";
case ZigLLVM_ppc64:
return "/lib64/ld64.so.2";
case ZigLLVM_ppc64le:
return "/lib64/ld64.so.2";
case ZigLLVM_systemz:
return "/lib64/ld64.so.1";
case ZigLLVM_sparcv9:
return "/lib64/ld-linux.so.2";
case ZigLLVM_x86_64:
if (abi == ZigLLVM_GNUX32) {
return "/libx32/ld-linux-x32.so.2";
}
if (abi == ZigLLVM_Musl || abi == ZigLLVM_MuslEABI || abi == ZigLLVM_MuslEABIHF) {
return "/lib/ld-musl-x86_64.so.1";
}
return "/lib64/ld-linux-x86-64.so.2";
case ZigLLVM_wasm32:
case ZigLLVM_wasm64:
return nullptr;
case ZigLLVM_riscv32:
return "/lib/ld-linux-riscv32-ilp32.so.1";
case ZigLLVM_riscv64:
return "/lib/ld-linux-riscv64-lp64.so.1";
case ZigLLVM_arc:
case ZigLLVM_avr:
case ZigLLVM_bpfel:
case ZigLLVM_bpfeb:
case ZigLLVM_hexagon:
case ZigLLVM_msp430:
case ZigLLVM_r600:
case ZigLLVM_amdgcn:
case ZigLLVM_tce:
case ZigLLVM_tcele:
case ZigLLVM_xcore:
case ZigLLVM_nvptx:
case ZigLLVM_nvptx64:
case ZigLLVM_le32:
case ZigLLVM_le64:
case ZigLLVM_amdil:
case ZigLLVM_amdil64:
case ZigLLVM_hsail:
case ZigLLVM_hsail64:
case ZigLLVM_spir:
case ZigLLVM_spir64:
case ZigLLVM_kalimba:
case ZigLLVM_shave:
case ZigLLVM_lanai:
case ZigLLVM_renderscript32:
case ZigLLVM_renderscript64:
zig_panic("TODO implement target_dynamic_linker for this arch");
}
zig_unreachable();
}
case OsFreestanding:
case OsIOS:
case OsTvOS:
case OsWatchOS:
case OsMacOSX:
case OsUefi:
case OsWindows:
case OsEmscripten:
case OsOther:
return nullptr;
case OsAnanas:
case OsCloudABI:
case OsFuchsia:
case OsKFreeBSD:
case OsLv2:
case OsOpenBSD:
case OsSolaris:
case OsHaiku:
case OsMinix:
case OsRTEMS:
case OsNaCl:
case OsCNK:
case OsAIX:
case OsCUDA:
case OsNVCL:
case OsAMDHSA:
case OsPS4:
case OsELFIAMCU:
case OsMesa3D:
case OsContiki:
case OsAMDPAL:
case OsHermitCore:
case OsHurd:
case OsWASI:
zig_panic("TODO implement target_dynamic_linker for this OS");
}
zig_unreachable();
}
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target) {
assert(host_target != nullptr);

View File

@ -8,51 +8,10 @@
#ifndef ZIG_TARGET_HPP
#define ZIG_TARGET_HPP
#include <zig_llvm.h>
#include "stage2.h"
struct Buf;
// Synchronize with target.cpp::os_list
enum Os {
OsFreestanding,
OsAnanas,
OsCloudABI,
OsDragonFly,
OsFreeBSD,
OsFuchsia,
OsIOS,
OsKFreeBSD,
OsLinux,
OsLv2, // PS3
OsMacOSX,
OsNetBSD,
OsOpenBSD,
OsSolaris,
OsWindows,
OsHaiku,
OsMinix,
OsRTEMS,
OsNaCl, // Native Client
OsCNK, // BG/P Compute-Node Kernel
OsAIX,
OsCUDA, // NVIDIA CUDA
OsNVCL, // NVIDIA OpenCL
OsAMDHSA, // AMD HSA Runtime
OsPS4,
OsELFIAMCU,
OsTvOS, // Apple tvOS
OsWatchOS, // Apple watchOS
OsMesa3D,
OsContiki,
OsAMDPAL,
OsHermitCore,
OsHurd,
OsWASI,
OsEmscripten,
OsUefi,
OsOther,
};
// Synchronize with target.cpp::subarch_list_list
enum SubArchList {
SubArchListNone,
@ -78,23 +37,6 @@ enum TargetSubsystem {
TargetSubsystemAuto
};
struct ZigGLibCVersion {
uint32_t major; // always 2
uint32_t minor;
uint32_t patch;
};
struct ZigTarget {
ZigLLVM_ArchType arch;
ZigLLVM_SubArchType sub_arch;
ZigLLVM_VendorType vendor;
Os os;
ZigLLVM_EnvironmentType abi;
ZigGLibCVersion *glibc_version; // null means default
Stage2CpuFeatures *cpu_features;
bool is_native;
};
enum CIntType {
CIntTypeShort,
CIntTypeUShort,
@ -168,8 +110,6 @@ const char *target_lib_file_prefix(const ZigTarget *target);
const char *target_lib_file_ext(const ZigTarget *target, bool is_static,
size_t version_major, size_t version_minor, size_t version_patch);
const char *target_dynamic_linker(const ZigTarget *target);
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
ZigLLVM_OSType get_llvm_os_type(Os os_type);