mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
Merge pull request #7406 from ifreund/dyn-musl2
stage2: support dynamically linking musl libc
This commit is contained in:
commit
4fd27719b4
5097
lib/libc/musl/libc.s
Normal file
5097
lib/libc/musl/libc.s
Normal file
File diff suppressed because it is too large
Load Diff
@ -500,8 +500,12 @@ pub const CrossTarget = struct {
|
||||
self.dynamic_linker.get() == null and self.glibc_version == null;
|
||||
}
|
||||
|
||||
pub fn isNativeAbi(self: CrossTarget) bool {
|
||||
return self.os_tag == null and self.abi == null;
|
||||
}
|
||||
|
||||
pub fn isNative(self: CrossTarget) bool {
|
||||
return self.isNativeCpu() and self.isNativeOs() and self.abi == null;
|
||||
return self.isNativeCpu() and self.isNativeOs() and self.isNativeAbi();
|
||||
}
|
||||
|
||||
pub fn zigTriple(self: CrossTarget, allocator: *mem.Allocator) error{OutOfMemory}![]u8 {
|
||||
|
@ -385,6 +385,7 @@ pub const InitOptions = struct {
|
||||
single_threaded: bool = false,
|
||||
function_sections: bool = false,
|
||||
is_native_os: bool,
|
||||
is_native_abi: bool,
|
||||
time_report: bool = false,
|
||||
stack_report: bool = false,
|
||||
link_eh_frame_hdr: bool = false,
|
||||
@ -600,7 +601,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
|
||||
break :dl false;
|
||||
};
|
||||
const default_link_mode: std.builtin.LinkMode = if (must_dynamic_link) .Dynamic else .Static;
|
||||
const default_link_mode: std.builtin.LinkMode = blk: {
|
||||
if (must_dynamic_link) {
|
||||
break :blk .Dynamic;
|
||||
} else if (is_exe_or_dyn_lib and link_libc and
|
||||
options.is_native_abi and options.target.abi.isMusl())
|
||||
{
|
||||
// If targeting the system's native ABI and the system's
|
||||
// libc is musl, link dynamically by default.
|
||||
break :blk .Dynamic;
|
||||
} else {
|
||||
break :blk .Static;
|
||||
}
|
||||
};
|
||||
const link_mode: std.builtin.LinkMode = if (options.link_mode) |lm| blk: {
|
||||
if (lm == .Static and must_dynamic_link) {
|
||||
return error.UnableToStaticLink;
|
||||
@ -910,6 +923,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
.rpath_list = options.rpath_list,
|
||||
.strip = strip,
|
||||
.is_native_os = options.is_native_os,
|
||||
.is_native_abi = options.is_native_abi,
|
||||
.function_sections = options.function_sections,
|
||||
.allow_shlib_undefined = options.linker_allow_shlib_undefined,
|
||||
.bind_global_refs_locally = options.linker_bind_global_refs_locally orelse false,
|
||||
@ -1025,7 +1039,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
.{ .musl_crt_file = .crt1_o },
|
||||
.{ .musl_crt_file = .scrt1_o },
|
||||
.{ .musl_crt_file = .rcrt1_o },
|
||||
.{ .musl_crt_file = .libc_a },
|
||||
switch (comp.bin_file.options.link_mode) {
|
||||
.Static => .{ .musl_crt_file = .libc_a },
|
||||
.Dynamic => .{ .musl_crt_file = .libc_so },
|
||||
},
|
||||
});
|
||||
}
|
||||
if (comp.wantBuildMinGWFromSource()) {
|
||||
@ -2775,6 +2792,7 @@ fn buildOutputFromZig(
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
.is_native_abi = comp.bin_file.options.is_native_abi,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
.verbose_link = comp.bin_file.options.verbose_link,
|
||||
@ -3145,6 +3163,7 @@ pub fn build_crt_file(
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
.is_native_abi = comp.bin_file.options.is_native_abi,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.c_source_files = c_source_files,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
|
@ -944,6 +944,7 @@ fn buildSharedLib(
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = false,
|
||||
.is_native_abi = false,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
.verbose_link = comp.bin_file.options.verbose_link,
|
||||
|
@ -175,6 +175,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
.is_native_abi = comp.bin_file.options.is_native_abi,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.c_source_files = c_source_files.items,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
@ -293,6 +294,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
.is_native_abi = comp.bin_file.options.is_native_abi,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.c_source_files = &c_source_files,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
|
@ -108,6 +108,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
.is_native_abi = comp.bin_file.options.is_native_abi,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.c_source_files = &c_source_files,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
|
@ -71,6 +71,7 @@ pub const Options = struct {
|
||||
z_defs: bool,
|
||||
bind_global_refs_locally: bool,
|
||||
is_native_os: bool,
|
||||
is_native_abi: bool,
|
||||
pic: bool,
|
||||
pie: bool,
|
||||
valgrind: bool,
|
||||
|
@ -1598,7 +1598,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
|
||||
} else if (target.isMusl()) {
|
||||
try argv.append(comp.libunwind_static_lib.?.full_object_path);
|
||||
try argv.append(try comp.get_libc_crt_file(arena, "libc.a"));
|
||||
try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
|
||||
.Static => "libc.a",
|
||||
.Dynamic => "libc.so",
|
||||
}));
|
||||
} else if (self.base.options.link_libcpp) {
|
||||
try argv.append(comp.libunwind_static_lib.?.full_object_path);
|
||||
} else {
|
||||
|
@ -1685,6 +1685,7 @@ fn buildOutputType(
|
||||
.root_name = root_name,
|
||||
.target = target_info.target,
|
||||
.is_native_os = cross_target.isNativeOs(),
|
||||
.is_native_abi = cross_target.isNativeAbi(),
|
||||
.dynamic_linker = target_info.dynamic_linker.get(),
|
||||
.output_mode = output_mode,
|
||||
.root_pkg = root_pkg,
|
||||
@ -2415,6 +2416,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
|
||||
.root_name = "build",
|
||||
.target = target_info.target,
|
||||
.is_native_os = cross_target.isNativeOs(),
|
||||
.is_native_abi = cross_target.isNativeAbi(),
|
||||
.dynamic_linker = target_info.dynamic_linker.get(),
|
||||
.output_mode = .Exe,
|
||||
.root_pkg = &root_pkg,
|
||||
|
54
src/musl.zig
54
src/musl.zig
@ -15,6 +15,7 @@ pub const CRTFile = enum {
|
||||
rcrt1_o,
|
||||
scrt1_o,
|
||||
libc_a,
|
||||
libc_so,
|
||||
};
|
||||
|
||||
pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
|
||||
@ -189,6 +190,59 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
|
||||
}
|
||||
return comp.build_crt_file("c", .Lib, c_source_files.items);
|
||||
},
|
||||
.libc_so => {
|
||||
const sub_compilation = try Compilation.create(comp.gpa, .{
|
||||
.local_cache_directory = comp.global_cache_directory,
|
||||
.global_cache_directory = comp.global_cache_directory,
|
||||
.zig_lib_directory = comp.zig_lib_directory,
|
||||
.target = comp.getTarget(),
|
||||
.root_name = "c",
|
||||
.root_pkg = null,
|
||||
.output_mode = .Lib,
|
||||
.link_mode = .Dynamic,
|
||||
.rand = comp.rand,
|
||||
.libc_installation = comp.bin_file.options.libc_installation,
|
||||
.emit_bin = Compilation.EmitLoc{ .directory = null, .basename = "libc.so" },
|
||||
.optimize_mode = comp.bin_file.options.optimize_mode,
|
||||
.want_sanitize_c = false,
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = false,
|
||||
.is_native_abi = false,
|
||||
.self_exe_path = comp.self_exe_path,
|
||||
.verbose_cc = comp.verbose_cc,
|
||||
.verbose_link = comp.bin_file.options.verbose_link,
|
||||
.verbose_tokenize = comp.verbose_tokenize,
|
||||
.verbose_ast = comp.verbose_ast,
|
||||
.verbose_ir = comp.verbose_ir,
|
||||
.verbose_llvm_ir = comp.verbose_llvm_ir,
|
||||
.verbose_cimport = comp.verbose_cimport,
|
||||
.verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
|
||||
.clang_passthrough_mode = comp.clang_passthrough_mode,
|
||||
.c_source_files = &[_]Compilation.CSourceFile{
|
||||
.{ .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "libc.s" }) },
|
||||
},
|
||||
.is_compiler_rt_or_libc = true,
|
||||
.soname = "libc.so",
|
||||
});
|
||||
defer sub_compilation.destroy();
|
||||
|
||||
try sub_compilation.updateSubCompilation();
|
||||
|
||||
try comp.crt_files.ensureCapacity(comp.gpa, comp.crt_files.count() + 1);
|
||||
|
||||
const basename = try comp.gpa.dupe(u8, "libc.so");
|
||||
errdefer comp.gpa.free(basename);
|
||||
|
||||
comp.crt_files.putAssumeCapacityNoClobber(basename, .{
|
||||
.full_object_path = try sub_compilation.bin_file.options.emit.?.directory.join(comp.gpa, &[_][]const u8{
|
||||
sub_compilation.bin_file.options.emit.?.sub_path,
|
||||
}),
|
||||
.lock = sub_compilation.bin_file.toOwnedLock(),
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,6 +561,7 @@ pub const TestContext = struct {
|
||||
.keep_source_files_loaded = true,
|
||||
.object_format = ofmt,
|
||||
.is_native_os = case.target.isNativeOs(),
|
||||
.is_native_abi = case.target.isNativeAbi(),
|
||||
});
|
||||
defer comp.destroy();
|
||||
|
||||
|
117
tools/gen_stubs.zig
Normal file
117
tools/gen_stubs.zig
Normal file
@ -0,0 +1,117 @@
|
||||
const std = @import("std");
|
||||
|
||||
const mem = std.mem;
|
||||
|
||||
const Symbol = struct {
|
||||
name: []const u8,
|
||||
section: []const u8,
|
||||
kind: enum {
|
||||
global,
|
||||
weak,
|
||||
},
|
||||
type: enum {
|
||||
none,
|
||||
function,
|
||||
object,
|
||||
},
|
||||
protected: bool,
|
||||
};
|
||||
|
||||
// Example usage:
|
||||
// objdump --dynamic-syms /path/to/libc.so | ./gen_stubs > lib/libc/musl/libc.s
|
||||
pub fn main() !void {
|
||||
const stdin = std.io.getStdIn().reader();
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
const ally = &arena.allocator;
|
||||
|
||||
var symbols = std.ArrayList(Symbol).init(ally);
|
||||
var sections = std.ArrayList([]const u8).init(ally);
|
||||
|
||||
// This is many times larger than any line objdump produces should ever be
|
||||
var buf: [4096]u8 = undefined;
|
||||
|
||||
// Sample input line:
|
||||
// 00000000000241b0 g DF .text 000000000000001b copy_file_range
|
||||
while (try stdin.readUntilDelimiterOrEof(&buf, '\n')) |line| {
|
||||
// the lines we want all start with a 16 digit hex value
|
||||
if (line.len < 16) continue;
|
||||
_ = std.fmt.parseInt(u64, line[0..16], 16) catch continue;
|
||||
|
||||
// Ignore non-dynamic symbols
|
||||
if (line[22] != 'D') continue;
|
||||
|
||||
const section = line[25 .. 25 + mem.indexOfAny(u8, line[25..], &std.ascii.spaces).?];
|
||||
|
||||
// the last whitespace-separated column is the symbol name
|
||||
const name = line[1 + mem.lastIndexOfAny(u8, line, &std.ascii.spaces).? ..];
|
||||
|
||||
const symbol = Symbol{
|
||||
.name = try ally.dupe(u8, name),
|
||||
.section = try ally.dupe(u8, section),
|
||||
|
||||
.kind = if (line[17] == 'g' and line[18] == ' ')
|
||||
.global
|
||||
else if (line[17] == ' ' and line[18] == 'w')
|
||||
.weak
|
||||
else
|
||||
unreachable,
|
||||
|
||||
.type = switch (line[23]) {
|
||||
'F' => .function,
|
||||
'O' => .object,
|
||||
' ' => .none,
|
||||
else => unreachable,
|
||||
},
|
||||
|
||||
.protected = mem.indexOf(u8, line, ".protected") != null,
|
||||
};
|
||||
|
||||
for (sections.items) |s| {
|
||||
if (mem.eql(u8, s, symbol.section)) break;
|
||||
} else {
|
||||
try sections.append(symbol.section);
|
||||
}
|
||||
|
||||
try symbols.append(symbol);
|
||||
}
|
||||
|
||||
std.sort.sort(Symbol, symbols.items, {}, cmpSymbols);
|
||||
std.sort.sort([]const u8, sections.items, {}, alphabetical);
|
||||
|
||||
for (sections.items) |section| {
|
||||
try stdout.print("{s}\n", .{section});
|
||||
|
||||
for (symbols.items) |symbol| {
|
||||
if (!mem.eql(u8, symbol.section, section)) continue;
|
||||
|
||||
switch (symbol.kind) {
|
||||
.global => try stdout.print(".globl {s}\n", .{symbol.name}),
|
||||
.weak => try stdout.print(".weak {s}\n", .{symbol.name}),
|
||||
}
|
||||
switch (symbol.type) {
|
||||
.function => try stdout.print(".type {s}, @function;\n", .{symbol.name}),
|
||||
.object => try stdout.print(".type {s}, @object;\n", .{symbol.name}),
|
||||
.none => {},
|
||||
}
|
||||
if (symbol.protected)
|
||||
try stdout.print(".protected {s}\n", .{symbol.name});
|
||||
try stdout.print("{s}:\n", .{symbol.name});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmpSymbols(_: void, lhs: Symbol, rhs: Symbol) bool {
|
||||
return alphabetical({}, lhs.name, rhs.name);
|
||||
}
|
||||
|
||||
fn alphabetical(_: void, lhs: []const u8, rhs: []const u8) bool {
|
||||
var i: usize = 0;
|
||||
while (i < lhs.len and i < rhs.len) : (i += 1) {
|
||||
if (lhs[i] == rhs[i]) continue;
|
||||
return lhs[i] < rhs[i];
|
||||
}
|
||||
return lhs.len < rhs.len;
|
||||
}
|
Loading…
Reference in New Issue
Block a user