stage2: support dynamically linking musl libc

This commit is contained in:
Isaac Freund 2020-12-11 15:31:23 +01:00
parent d569e37cb5
commit 307d98dc35
No known key found for this signature in database
GPG key ID: 86DED400DDFD7A11
5 changed files with 5275 additions and 2 deletions

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

File diff suppressed because it is too large Load diff

View file

@ -1025,7 +1025,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()) {

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

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

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