Merge pull request #7406 from ifreund/dyn-musl2

stage2: support dynamically linking musl libc
This commit is contained in:
Andrew Kelley 2020-12-12 18:46:07 -05:00 committed by GitHub
commit 4fd27719b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 5306 additions and 4 deletions

5097
lib/libc/musl/libc.s Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 {

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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 {

View File

@ -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,

View File

@ -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(),
});
},
}
}

View File

@ -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
View 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;
}