authorgravatar for michael.dusan@gmail.comMichael Dusan <michael.dusan@gmail.com> 2021-05-16 15:59:34-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-23 15:38:57-04:00
log0f2612037784570930dea433afef559ff6161b21
treed60fbc768c7460ac6874ed937eac38f8fe345842
parent44e480aa2cef24a0a9edbc5d24991f9432a255e3

overhaul elf csu (c-runtime startup) logic

- more support for linux, android, freebsd, netbsd, openbsd, dragonfly - centralize musl utils; musl logic is no longer intertwined with csu - fix musl compilation to build crti/crtn for full archs list - fix openbsd to support `zig build-lib -dynamic` - initial dragonfly linking success (with a warning) ancillary: - fix emutls (openbsd) tests to use `try`

11 files changed, 288 insertions(+), 91 deletions(-)

lib/std/Thread.zig+3
...@@ -576,6 +576,9 @@ pub fn getCurrentThreadId() u64 {...@@ -576,6 +576,9 @@ pub fn getCurrentThreadId() u64 {
576 assert(c.pthread_threadid_np(null, &thread_id) == 0);576 assert(c.pthread_threadid_np(null, &thread_id) == 0);
577 return thread_id;577 return thread_id;
578 },578 },
579 .dragonfly => {
580 return @bitCast(u32, c.lwp_gettid());
581 },
579 .netbsd => {582 .netbsd => {
580 return @bitCast(u32, c._lwp_self());583 return @bitCast(u32, c._lwp_self());
581 },584 },
lib/std/c/dragonfly.zig+4
...@@ -18,6 +18,8 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;...@@ -18,6 +18,8 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
18pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int;18pub const dl_iterate_phdr_callback = fn (info: *dl_phdr_info, size: usize, data: ?*c_void) callconv(.C) c_int;
19pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;19pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int;
2020
21pub extern "c" fn lwp_gettid() c_int;
22
21pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int;23pub extern "c" fn posix_memalign(memptr: *?*c_void, alignment: usize, size: usize) c_int;
2224
23pub const pthread_mutex_t = extern struct {25pub const pthread_mutex_t = extern struct {
...@@ -31,3 +33,5 @@ pub const pthread_attr_t = extern struct { // copied from freebsd...@@ -31,3 +33,5 @@ pub const pthread_attr_t = extern struct { // copied from freebsd
31 __size: [56]u8,33 __size: [56]u8,
32 __align: c_long,34 __align: c_long,
33};35};
36
37pub const sem_t = ?*opaque {};
lib/std/child_process.zig+14-2
...@@ -203,6 +203,10 @@ pub const ChildProcess = struct {...@@ -203,6 +203,10 @@ pub const ChildProcess = struct {
203 // of space an ArrayList will allocate grows exponentially.203 // of space an ArrayList will allocate grows exponentially.
204 const bump_amt = 512;204 const bump_amt = 512;
205205
206 // TODO https://github.com/ziglang/zig/issues/8724
207 // parent process does not receive POLLHUP events
208 const dragonfly_workaround = builtin.os.tag == .dragonfly;
209
206 while (dead_fds < poll_fds.len) {210 while (dead_fds < poll_fds.len) {
207 const events = try os.poll(&poll_fds, std.math.maxInt(i32));211 const events = try os.poll(&poll_fds, std.math.maxInt(i32));
208 if (events == 0) continue;212 if (events == 0) continue;
...@@ -215,7 +219,11 @@ pub const ChildProcess = struct {...@@ -215,7 +219,11 @@ pub const ChildProcess = struct {
215 try stdout.ensureCapacity(new_capacity);219 try stdout.ensureCapacity(new_capacity);
216 const buf = stdout.unusedCapacitySlice();220 const buf = stdout.unusedCapacitySlice();
217 if (buf.len == 0) return error.StdoutStreamTooLong;221 if (buf.len == 0) return error.StdoutStreamTooLong;
218 stdout.items.len += try os.read(poll_fds[0].fd, buf);222 const nread = try os.read(poll_fds[0].fd, buf);
223 stdout.items.len += nread;
224
225 // insert POLLHUP event because dragonfly fails to do so
226 if (dragonfly_workaround and nread == 0) poll_fds[0].revents |= os.POLLHUP;
219 }227 }
220 if (poll_fds[1].revents & os.POLLIN != 0) {228 if (poll_fds[1].revents & os.POLLIN != 0) {
221 // stderr is ready.229 // stderr is ready.
...@@ -223,7 +231,11 @@ pub const ChildProcess = struct {...@@ -223,7 +231,11 @@ pub const ChildProcess = struct {
223 try stderr.ensureCapacity(new_capacity);231 try stderr.ensureCapacity(new_capacity);
224 const buf = stderr.unusedCapacitySlice();232 const buf = stderr.unusedCapacitySlice();
225 if (buf.len == 0) return error.StderrStreamTooLong;233 if (buf.len == 0) return error.StderrStreamTooLong;
226 stderr.items.len += try os.read(poll_fds[1].fd, buf);234 const nread = try os.read(poll_fds[1].fd, buf);
235 stderr.items.len += nread;
236
237 // insert POLLHUP event because dragonfly fails to do so
238 if (dragonfly_workaround and nread == 0) poll_fds[1].revents |= os.POLLHUP;
227 }239 }
228240
229 // Exclude the fds that signaled an error.241 // Exclude the fds that signaled an error.
lib/std/os/bits/dragonfly.zig+26
...@@ -767,3 +767,29 @@ pub const rlimit = extern struct {...@@ -767,3 +767,29 @@ pub const rlimit = extern struct {
767 /// Hard limit767 /// Hard limit
768 max: rlim_t,768 max: rlim_t,
769};769};
770
771pub const SHUT_RD = 0;
772pub const SHUT_WR = 1;
773pub const SHUT_RDWR = 2;
774
775pub const nfds_t = u32;
776
777pub const pollfd = extern struct {
778 fd: fd_t,
779 events: i16,
780 revents: i16,
781};
782
783/// Requestable events.
784pub const POLLIN = 0x0001;
785pub const POLLPRI = 0x0002;
786pub const POLLOUT = 0x0004;
787pub const POLLRDNORM = 0x0040;
788pub const POLLWRNORM = POLLOUT;
789pub const POLLRDBAND = 0x0080;
790pub const POLLWRBAND = 0x0100;
791
792/// These events are set if they occur regardless of whether they were requested.
793pub const POLLERR = 0x0008;
794pub const POLLHUP = 0x0010;
795pub const POLLNVAL = 0x0020;
lib/std/special/compiler_rt/emutls.zig+6-6
...@@ -376,7 +376,7 @@ test "__emutls_get_address with default_value" {...@@ -376,7 +376,7 @@ test "__emutls_get_address with default_value" {
376376
377test "test default_value with differents sizes" {377test "test default_value with differents sizes" {
378 const testType = struct {378 const testType = struct {
379 fn _testType(comptime T: type, value: T) void {379 fn _testType(comptime T: type, value: T) !void {
380 var def: T = value;380 var def: T = value;
381 var ctl = emutls_control.init(T, &def);381 var ctl = emutls_control.init(T, &def);
382 var x = ctl.get_typed_pointer(T);382 var x = ctl.get_typed_pointer(T);
...@@ -384,11 +384,11 @@ test "test default_value with differents sizes" {...@@ -384,11 +384,11 @@ test "test default_value with differents sizes" {
384 }384 }
385 }._testType;385 }._testType;
386386
387 testType(usize, 1234);387 try testType(usize, 1234);
388 testType(u32, 1234);388 try testType(u32, 1234);
389 testType(i16, -12);389 try testType(i16, -12);
390 testType(f64, -12.0);390 try testType(f64, -12.0);
391 testType(391 try testType(
392 @TypeOf("012345678901234567890123456789"),392 @TypeOf("012345678901234567890123456789"),
393 "012345678901234567890123456789",393 "012345678901234567890123456789",
394 );394 );
src/Compilation.zig+2-2
...@@ -1407,7 +1407,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1407,7 +1407,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1407 }1407 }
1408 if (comp.wantBuildMuslFromSource()) {1408 if (comp.wantBuildMuslFromSource()) {
1409 try comp.work_queue.ensureUnusedCapacity(6);1409 try comp.work_queue.ensureUnusedCapacity(6);
1410 if (target_util.libc_needs_crti_crtn(comp.getTarget())) {1410 if (musl.needsCrtiCrtn(comp.getTarget())) {
1411 comp.work_queue.writeAssumeCapacity(&[_]Job{1411 comp.work_queue.writeAssumeCapacity(&[_]Job{
1412 .{ .musl_crt_file = .crti_o },1412 .{ .musl_crt_file = .crti_o },
1413 .{ .musl_crt_file = .crtn_o },1413 .{ .musl_crt_file = .crtn_o },
...@@ -3180,7 +3180,7 @@ fn detectLibCIncludeDirs(...@@ -3180,7 +3180,7 @@ fn detectLibCIncludeDirs(
3180 const generic_name = target_util.libCGenericName(target);3180 const generic_name = target_util.libCGenericName(target);
3181 // Some architectures are handled by the same set of headers.3181 // Some architectures are handled by the same set of headers.
3182 const arch_name = if (target.abi.isMusl())3182 const arch_name = if (target.abi.isMusl())
3183 target_util.archMuslName(target.cpu.arch)3183 musl.archMuslName(target.cpu.arch)
3184 else if (target.cpu.arch.isThumb())3184 else if (target.cpu.arch.isThumb())
3185 // ARM headers are valid for Thumb too.3185 // ARM headers are valid for Thumb too.
3186 switch (target.cpu.arch) {3186 switch (target.cpu.arch) {
src/libc_installation.zig+3-3
...@@ -195,8 +195,8 @@ pub const LibCInstallation = struct {...@@ -195,8 +195,8 @@ pub const LibCInstallation = struct {
195 errdefer batch.wait() catch {};195 errdefer batch.wait() catch {};
196 batch.add(&async self.findNativeIncludeDirPosix(args));196 batch.add(&async self.findNativeIncludeDirPosix(args));
197 switch (Target.current.os.tag) {197 switch (Target.current.os.tag) {
198 .freebsd, .netbsd, .openbsd => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"),198 .freebsd, .netbsd, .openbsd, .dragonfly => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/usr/lib"),
199 .linux, .dragonfly => batch.add(&async self.findNativeCrtDirPosix(args)),199 .linux => batch.add(&async self.findNativeCrtDirPosix(args)),
200 .haiku => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/system/develop/lib"),200 .haiku => self.crt_dir = try std.mem.dupeZ(args.allocator, u8, "/system/develop/lib"),
201 else => {},201 else => {},
202 }202 }
...@@ -523,7 +523,7 @@ pub const CCPrintFileNameOptions = struct {...@@ -523,7 +523,7 @@ pub const CCPrintFileNameOptions = struct {
523};523};
524524
525/// caller owns returned memory525/// caller owns returned memory
526fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {526pub fn ccPrintFileName(args: CCPrintFileNameOptions) ![:0]u8 {
527 const allocator = args.allocator;527 const allocator = args.allocator;
528528
529 const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;529 const cc_exe = std.os.getenvZ("CC") orelse default_cc_exe;
src/link/Elf.zig+188-45
...@@ -23,6 +23,7 @@ const File = link.File;...@@ -23,6 +23,7 @@ const File = link.File;
23const build_options = @import("build_options");23const build_options = @import("build_options");
24const target_util = @import("../target.zig");24const target_util = @import("../target.zig");
25const glibc = @import("../glibc.zig");25const glibc = @import("../glibc.zig");
26const musl = @import("../musl.zig");
26const Cache = @import("../Cache.zig");27const Cache = @import("../Cache.zig");
27const llvm_backend = @import("../codegen/llvm.zig");28const llvm_backend = @import("../codegen/llvm.zig");
2829
...@@ -1278,7 +1279,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1278,7 +1279,6 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1278 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;1279 const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
1279 const have_dynamic_linker = self.base.options.link_libc and1280 const have_dynamic_linker = self.base.options.link_libc and
1280 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;1281 self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
1281 const link_in_crt = self.base.options.link_libc and self.base.options.output_mode == .Exe;
1282 const target = self.base.options.target;1282 const target = self.base.options.target;
1283 const gc_sections = self.base.options.gc_sections orelse !is_obj;1283 const gc_sections = self.base.options.gc_sections orelse !is_obj;
1284 const stack_size = self.base.options.stack_size_override orelse 16777216;1284 const stack_size = self.base.options.stack_size_override orelse 16777216;
...@@ -1499,40 +1499,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1499,40 +1499,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1499 try argv.append("-o");1499 try argv.append("-o");
1500 try argv.append(full_out_path);1500 try argv.append(full_out_path);
15011501
1502 if (link_in_crt) {1502 // csu prelude
1503 const crt1o: []const u8 = o: {1503 var csu = try CsuObjects.init(arena, self.base.options, comp);
1504 if (target.os.tag == .netbsd) {1504 if (csu.crt0) |v| try argv.append(v);
1505 break :o "crt0.o";1505 if (csu.crti) |v| try argv.append(v);
1506 } else if (target.os.tag == .openbsd) {1506 if (csu.crtbegin) |v| try argv.append(v);
1507 if (self.base.options.link_mode == .Static) {
1508 break :o "rcrt0.o";
1509 } else {
1510 break :o "crt0.o";
1511 }
1512 } else if (target.isAndroid()) {
1513 if (self.base.options.link_mode == .Dynamic) {
1514 break :o "crtbegin_dynamic.o";
1515 } else {
1516 break :o "crtbegin_static.o";
1517 }
1518 } else if (self.base.options.link_mode == .Static) {
1519 if (self.base.options.pie) {
1520 break :o "rcrt1.o";
1521 } else {
1522 break :o "crt1.o";
1523 }
1524 } else {
1525 break :o "Scrt1.o";
1526 }
1527 };
1528 try argv.append(try comp.get_libc_crt_file(arena, crt1o));
1529 if (target_util.libc_needs_crti_crtn(target)) {
1530 try argv.append(try comp.get_libc_crt_file(arena, "crti.o"));
1531 }
1532 if (target.os.tag == .openbsd) {
1533 try argv.append(try comp.get_libc_crt_file(arena, "crtbegin.o"));
1534 }
1535 }
15361507
1537 // rpaths1508 // rpaths
1538 var rpath_table = std.StringHashMap(void).init(self.base.allocator);1509 var rpath_table = std.StringHashMap(void).init(self.base.allocator);
...@@ -1676,16 +1647,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1676,16 +1647,9 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1676 }1647 }
1677 }1648 }
16781649
1679 // crt end1650 // crt postlude
1680 if (link_in_crt) {1651 if (csu.crtend) |v| try argv.append(v);
1681 if (target.isAndroid()) {1652 if (csu.crtn) |v| try argv.append(v);
1682 try argv.append(try comp.get_libc_crt_file(arena, "crtend_android.o"));
1683 } else if (target.os.tag == .openbsd) {
1684 try argv.append(try comp.get_libc_crt_file(arena, "crtend.o"));
1685 } else if (target_util.libc_needs_crti_crtn(target)) {
1686 try argv.append(try comp.get_libc_crt_file(arena, "crtn.o"));
1687 }
1688 }
16891653
1690 if (allow_shlib_undefined) {1654 if (allow_shlib_undefined) {
1691 try argv.append("--allow-shlib-undefined");1655 try argv.append("--allow-shlib-undefined");
...@@ -3237,3 +3201,182 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -3237,3 +3201,182 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
3237 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch3201 return std.math.add(@TypeOf(actual_size), actual_size, actual_size / ideal_factor) catch
3238 std.math.maxInt(@TypeOf(actual_size));3202 std.math.maxInt(@TypeOf(actual_size));
3239}3203}
3204
3205// Provide a blueprint of csu (c-runtime startup) objects for supported
3206// link modes.
3207//
3208// This is for cross-mode targets only. For host-mode targets the system
3209// compiler can be probed to produce a robust blueprint.
3210//
3211// Targets requiring a libc for which zig does not bundle a libc are
3212// host-mode targets. Unfortunately, host-mode probes are not yet
3213// implemented. For now the data is hard-coded here. Such targets are
3214// { freebsd, netbsd, openbsd, dragonfly }.
3215const CsuObjects = struct {
3216 crt0: ?[]const u8 = null,
3217 crti: ?[]const u8 = null,
3218 crtbegin: ?[]const u8 = null,
3219 crtend: ?[]const u8 = null,
3220 crtn: ?[]const u8 = null,
3221
3222 fn init(arena: *mem.Allocator, link_options: link.Options, comp: *const Compilation) !CsuObjects {
3223 // crt objects are only required for libc.
3224 if (!link_options.link_libc) return CsuObjects{};
3225
3226 var result: CsuObjects = .{};
3227
3228 // TODO: https://github.com/ziglang/zig/issues/4629
3229 // - use inline enum type
3230 // - reduce to enum-literals for values
3231 const Mode = enum {
3232 dynamic_lib,
3233 dynamic_exe,
3234 dynamic_pie,
3235 static_exe,
3236 static_pie,
3237 };
3238
3239 // Flatten crt case types.
3240 const mode: Mode = switch (link_options.output_mode) {
3241 .Obj => return CsuObjects{},
3242 .Lib => switch (link_options.link_mode) {
3243 .Dynamic => Mode.dynamic_lib,
3244 .Static => return CsuObjects{},
3245 },
3246 .Exe => switch (link_options.link_mode) {
3247 .Dynamic => if (link_options.pie) Mode.dynamic_pie else Mode.dynamic_exe,
3248 .Static => if (link_options.pie) Mode.static_pie else Mode.static_exe,
3249 },
3250 };
3251
3252 if (link_options.target.isAndroid()) {
3253 switch (mode) {
3254 // zig fmt: off
3255 .dynamic_lib => result.set( null, null, "crtbegin_so.o", "crtend_so.o", null ),
3256 .dynamic_exe,
3257 .dynamic_pie => result.set( null, null, "crtbegin_dynamic.o", "crtend_android.o", null ),
3258 .static_exe,
3259 .static_pie => result.set( null, null, "crtbegin_static.o", "crtend_android.o", null ),
3260 // zig fmt: on
3261 }
3262 } else {
3263 switch (link_options.target.os.tag) {
3264 .linux => {
3265 switch (mode) {
3266 // zig fmt: off
3267 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3268 .dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
3269 .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3270 .static_exe => result.set( "crt1.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
3271 .static_pie => result.set( "rcrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3272 // zig fmt: on
3273 }
3274 if (link_options.libc_installation) |_| {
3275 // hosted-glibc provides crtbegin/end objects in platform/compiler-specific dirs
3276 // and they are not known at comptime. For now null-out crtbegin/end objects;
3277 // there is no feature loss, zig has never linked those objects in before.
3278 // TODO: probe for paths, ie. `cc -print-file-name`
3279 result.crtbegin = null;
3280 result.crtend = null;
3281 } else {
3282 // Bundled glibc only has Scrt1.o .
3283 if (result.crt0 != null and link_options.target.isGnuLibC()) result.crt0 = "Scrt1.o";
3284 }
3285 },
3286 .dragonfly => switch (mode) {
3287 // zig fmt: off
3288 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3289 .dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
3290 .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3291 .static_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
3292 .static_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3293 // zig fmt: on
3294 },
3295 .freebsd => switch (mode) {
3296 // zig fmt: off
3297 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3298 .dynamic_exe => result.set( "crt1.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
3299 .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3300 .static_exe => result.set( "crt1.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
3301 .static_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3302 // zig fmt: on
3303 },
3304 .netbsd => switch (mode) {
3305 // zig fmt: off
3306 .dynamic_lib => result.set( null, "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3307 .dynamic_exe => result.set( "crt0.o", "crti.o", "crtbegin.o", "crtend.o", "crtn.o" ),
3308 .dynamic_pie => result.set( "crt0.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
3309 .static_exe => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtend.o", "crtn.o" ),
3310 .static_pie => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtendS.o", "crtn.o" ),
3311 // zig fmt: on
3312 },
3313 .openbsd => switch(mode) {
3314 // zig fmt: off
3315 .dynamic_lib => result.set( null, null, "crtbeginS.o", "crtendS.o", null ),
3316 .dynamic_exe,
3317 .dynamic_pie => result.set( "crt0.o", null, "crtbegin.o", "crtend.o", null ),
3318 .static_exe,
3319 .static_pie => result.set( "rcrt0.o", null, "crtbegin.o", "crtend.o", null ),
3320 // zig fmt: on
3321 },
3322 else => {},
3323 }
3324 }
3325
3326 // Convert each object to a full pathname.
3327 if (link_options.libc_installation) |lci| {
3328 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
3329 switch (link_options.target.os.tag) {
3330 .dragonfly => {
3331 if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
3332 if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
3333 if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
3334
3335 var gccv: []const u8 = undefined;
3336 if (link_options.target.os.version_range.semver.isAtLeast(.{ .major = 5, .minor = 4 }) orelse true) {
3337 gccv = "gcc80";
3338 } else {
3339 gccv = "gcc54";
3340 }
3341
3342 if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
3343 if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
3344 },
3345 else => {
3346 inline for (std.meta.fields(@TypeOf(result))) |f,i| {
3347 if (@field(result, f.name)) |*obj| {
3348 obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
3349 }
3350 }
3351 }
3352 }
3353 } else {
3354 inline for (std.meta.fields(@TypeOf(result))) |f,i| {
3355 if (@field(result, f.name)) |*obj| {
3356 if (comp.crt_files.get(obj.*)) |crtf| {
3357 obj.* = crtf.full_object_path;
3358 } else {
3359 @field(result, f.name) = null;
3360 }
3361 }
3362 }
3363 }
3364
3365 return result;
3366 }
3367
3368 fn set(
3369 self: *CsuObjects,
3370 crt0: ?[]const u8,
3371 crti: ?[]const u8,
3372 crtbegin: ?[]const u8,
3373 crtend: ?[]const u8,
3374 crtn: ?[]const u8,
3375 ) void {
3376 self.crt0 = crt0;
3377 self.crti = crti;
3378 self.crtbegin = crtbegin;
3379 self.crtend = crtend;
3380 self.crtn = crtn;
3381 }
3382};
src/musl.zig+41-12
...@@ -30,7 +30,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -30,7 +30,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
30 switch (crt_file) {30 switch (crt_file) {
31 .crti_o => {31 .crti_o => {
32 var args = std.ArrayList([]const u8).init(arena);32 var args = std.ArrayList([]const u8).init(arena);
33 try add_cc_args(comp, arena, &args, false);33 try addCcArgs(comp, arena, &args, false);
34 try args.appendSlice(&[_][]const u8{34 try args.appendSlice(&[_][]const u8{
35 "-Qunused-arguments",35 "-Qunused-arguments",
36 });36 });
...@@ -43,7 +43,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -43,7 +43,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
43 },43 },
44 .crtn_o => {44 .crtn_o => {
45 var args = std.ArrayList([]const u8).init(arena);45 var args = std.ArrayList([]const u8).init(arena);
46 try add_cc_args(comp, arena, &args, false);46 try addCcArgs(comp, arena, &args, false);
47 try args.appendSlice(&[_][]const u8{47 try args.appendSlice(&[_][]const u8{
48 "-Qunused-arguments",48 "-Qunused-arguments",
49 });49 });
...@@ -56,7 +56,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -56,7 +56,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
56 },56 },
57 .crt1_o => {57 .crt1_o => {
58 var args = std.ArrayList([]const u8).init(arena);58 var args = std.ArrayList([]const u8).init(arena);
59 try add_cc_args(comp, arena, &args, false);59 try addCcArgs(comp, arena, &args, false);
60 try args.appendSlice(&[_][]const u8{60 try args.appendSlice(&[_][]const u8{
61 "-fno-stack-protector",61 "-fno-stack-protector",
62 "-DCRT",62 "-DCRT",
...@@ -72,7 +72,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -72,7 +72,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
72 },72 },
73 .rcrt1_o => {73 .rcrt1_o => {
74 var args = std.ArrayList([]const u8).init(arena);74 var args = std.ArrayList([]const u8).init(arena);
75 try add_cc_args(comp, arena, &args, false);75 try addCcArgs(comp, arena, &args, false);
76 try args.appendSlice(&[_][]const u8{76 try args.appendSlice(&[_][]const u8{
77 "-fPIC",77 "-fPIC",
78 "-fno-stack-protector",78 "-fno-stack-protector",
...@@ -89,7 +89,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -89,7 +89,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
89 },89 },
90 .scrt1_o => {90 .scrt1_o => {
91 var args = std.ArrayList([]const u8).init(arena);91 var args = std.ArrayList([]const u8).init(arena);
92 try add_cc_args(comp, arena, &args, false);92 try addCcArgs(comp, arena, &args, false);
93 try args.appendSlice(&[_][]const u8{93 try args.appendSlice(&[_][]const u8{
94 "-fPIC",94 "-fPIC",
95 "-fno-stack-protector",95 "-fno-stack-protector",
...@@ -108,7 +108,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -108,7 +108,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
108 // When there is a src/<arch>/foo.* then it should substitute for src/foo.*108 // When there is a src/<arch>/foo.* then it should substitute for src/foo.*
109 // Even a .s file can substitute for a .c file.109 // Even a .s file can substitute for a .c file.
110 const target = comp.getTarget();110 const target = comp.getTarget();
111 const arch_name = target_util.archMuslName(target.cpu.arch);111 const arch_name = archMuslName(target.cpu.arch);
112 var source_table = std.StringArrayHashMap(Ext).init(comp.gpa);112 var source_table = std.StringArrayHashMap(Ext).init(comp.gpa);
113 defer source_table.deinit();113 defer source_table.deinit();
114114
...@@ -147,7 +147,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -147,7 +147,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
147147
148 var is_arch_specific = false;148 var is_arch_specific = false;
149 // Architecture-specific implementations are under a <arch>/ folder.149 // Architecture-specific implementations are under a <arch>/ folder.
150 if (is_musl_arch_name(dirbasename)) {150 if (isMuslArchName(dirbasename)) {
151 if (!mem.eql(u8, dirbasename, arch_name))151 if (!mem.eql(u8, dirbasename, arch_name))
152 continue; // Not the architecture we're compiling for.152 continue; // Not the architecture we're compiling for.
153 is_arch_specific = true;153 is_arch_specific = true;
...@@ -177,7 +177,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -177,7 +177,7 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
177 }177 }
178178
179 var args = std.ArrayList([]const u8).init(arena);179 var args = std.ArrayList([]const u8).init(arena);
180 try add_cc_args(comp, arena, &args, ext == .o3);180 try addCcArgs(comp, arena, &args, ext == .o3);
181 try args.appendSlice(&[_][]const u8{181 try args.appendSlice(&[_][]const u8{
182 "-Qunused-arguments",182 "-Qunused-arguments",
183 "-w", // disable all warnings183 "-w", // disable all warnings
...@@ -248,7 +248,36 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {...@@ -248,7 +248,36 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
248 }248 }
249}249}
250250
251fn is_musl_arch_name(name: []const u8) bool {251pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
252 switch (arch) {
253 .aarch64, .aarch64_be => return "aarch64",
254 .arm, .armeb, .thumb, .thumbeb => return "arm",
255 .i386 => return "i386",
256 .mips, .mipsel => return "mips",
257 .mips64el, .mips64 => return "mips64",
258 .powerpc => return "powerpc",
259 .powerpc64, .powerpc64le => return "powerpc64",
260 .riscv64 => return "riscv64",
261 .s390x => return "s390x",
262 .wasm32, .wasm64 => return "wasm",
263 .x86_64 => return "x86_64",
264 else => unreachable,
265 }
266}
267
268// Return true if musl has arch-specific crti/crtn sources.
269// See lib/libc/musl/crt/ARCH/crt?.s .
270pub fn needsCrtiCrtn(target: std.Target) bool {
271 // zig fmt: off
272 return switch (target.cpu.arch) {
273 .riscv64,
274 .wasm32, .wasm64 => return false,
275 else => true,
276 };
277 // zig fmt: on
278}
279
280fn isMuslArchName(name: []const u8) bool {
252 const musl_arch_names = [_][]const u8{281 const musl_arch_names = [_][]const u8{
253 "aarch64",282 "aarch64",
254 "arm",283 "arm",
...@@ -314,14 +343,14 @@ fn addSrcFile(arena: *Allocator, source_table: *std.StringArrayHashMap(Ext), fil...@@ -314,14 +343,14 @@ fn addSrcFile(arena: *Allocator, source_table: *std.StringArrayHashMap(Ext), fil
314 source_table.putAssumeCapacityNoClobber(key, ext);343 source_table.putAssumeCapacityNoClobber(key, ext);
315}344}
316345
317fn add_cc_args(346fn addCcArgs(
318 comp: *Compilation,347 comp: *Compilation,
319 arena: *Allocator,348 arena: *Allocator,
320 args: *std.ArrayList([]const u8),349 args: *std.ArrayList([]const u8),
321 want_O3: bool,350 want_O3: bool,
322) error{OutOfMemory}!void {351) error{OutOfMemory}!void {
323 const target = comp.getTarget();352 const target = comp.getTarget();
324 const arch_name = target_util.archMuslName(target.cpu.arch);353 const arch_name = archMuslName(target.cpu.arch);
325 const os_name = @tagName(target.os.tag);354 const os_name = @tagName(target.os.tag);
326 const triple = try std.fmt.allocPrint(arena, "{s}-{s}-musl", .{ arch_name, os_name });355 const triple = try std.fmt.allocPrint(arena, "{s}-{s}-musl", .{ arch_name, os_name });
327 const o_arg = if (want_O3) "-O3" else "-Os";356 const o_arg = if (want_O3) "-O3" else "-Os";
...@@ -369,7 +398,7 @@ fn add_cc_args(...@@ -369,7 +398,7 @@ fn add_cc_args(
369fn start_asm_path(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 {398fn start_asm_path(comp: *Compilation, arena: *Allocator, basename: []const u8) ![]const u8 {
370 const target = comp.getTarget();399 const target = comp.getTarget();
371 return comp.zig_lib_directory.join(arena, &[_][]const u8{400 return comp.zig_lib_directory.join(arena, &[_][]const u8{
372 "libc", "musl", "crt", target_util.archMuslName(target.cpu.arch), basename,401 "libc", "musl", "crt", archMuslName(target.cpu.arch), basename,
373 });402 });
374}403}
375404
src/target.zig-21
...@@ -99,23 +99,6 @@ pub fn libCGenericName(target: std.Target) [:0]const u8 {...@@ -99,23 +99,6 @@ pub fn libCGenericName(target: std.Target) [:0]const u8 {
99 }99 }
100}100}
101101
102pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
103 switch (arch) {
104 .aarch64, .aarch64_be => return "aarch64",
105 .arm, .armeb, .thumb, .thumbeb => return "arm",
106 .mips, .mipsel => return "mips",
107 .mips64el, .mips64 => return "mips64",
108 .powerpc => return "powerpc",
109 .powerpc64, .powerpc64le => return "powerpc64",
110 .s390x => return "s390x",
111 .i386 => return "i386",
112 .x86_64 => return "x86_64",
113 .riscv64 => return "riscv64",
114 .wasm32, .wasm64 => return "wasm",
115 else => unreachable,
116 }
117}
118
119pub fn canBuildLibC(target: std.Target) bool {102pub fn canBuildLibC(target: std.Target) bool {
120 for (available_libcs) |libc| {103 for (available_libcs) |libc| {
121 if (target.cpu.arch == libc.arch and target.os.tag == libc.os and target.abi == libc.abi) {104 if (target.cpu.arch == libc.arch and target.os.tag == libc.os and target.abi == libc.abi) {
...@@ -172,10 +155,6 @@ pub fn supports_fpic(target: std.Target) bool {...@@ -172,10 +155,6 @@ pub fn supports_fpic(target: std.Target) bool {
172 return target.os.tag != .windows;155 return target.os.tag != .windows;
173}156}
174157
175pub fn libc_needs_crti_crtn(target: std.Target) bool {
176 return !(target.cpu.arch.isRISCV() or target.isAndroid() or target.os.tag == .openbsd);
177}
178
179pub fn isSingleThreaded(target: std.Target) bool {158pub fn isSingleThreaded(target: std.Target) bool {
180 return target.isWasm();159 return target.isWasm();
181}160}
test/stack_traces.zig+1
...@@ -171,6 +171,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -171,6 +171,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
171171
172 cases.addCase(.{172 cases.addCase(.{
173 .exclude_os = .{173 .exclude_os = .{
174 .openbsd, // integer overflow
174 .windows,175 .windows,
175 },176 },
176 .name = "dumpCurrentStackTrace",177 .name = "dumpCurrentStackTrace",