authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-08 10:53:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-08 10:53:22-07:00
logb6bb0ee1acd6fb9e3360f35d7b63687f755785f6
tree34f42b24cc683d13a9e78bd27f914dfee00c37b0
parent28353b315935e54b497f4abb875fac387e20f65f
parent84d5cc31c560749eda1e36b7bc9e6cf542eee550

Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen

Conflicts: * lib/std/os/linux/tls.zig * test/behavior/align.zig * test/behavior/atomics.zig * test/behavior/vector.zig

22 files changed, 305 insertions(+), 55 deletions(-)

lib/std/os/bits/linux.zig+1-1
...@@ -18,7 +18,7 @@ pub usingnamespace switch (arch) {...@@ -18,7 +18,7 @@ pub usingnamespace switch (arch) {
18 .i386 => @import("linux/i386.zig"),18 .i386 => @import("linux/i386.zig"),
19 .x86_64 => @import("linux/x86_64.zig"),19 .x86_64 => @import("linux/x86_64.zig"),
20 .aarch64 => @import("linux/arm64.zig"),20 .aarch64 => @import("linux/arm64.zig"),
21 .arm => @import("linux/arm-eabi.zig"),21 .arm, .thumb => @import("linux/arm-eabi.zig"),
22 .riscv64 => @import("linux/riscv64.zig"),22 .riscv64 => @import("linux/riscv64.zig"),
23 .sparcv9 => @import("linux/sparc64.zig"),23 .sparcv9 => @import("linux/sparc64.zig"),
24 .mips, .mipsel => @import("linux/mips.zig"),24 .mips, .mipsel => @import("linux/mips.zig"),
lib/std/os/linux.zig+1
...@@ -24,6 +24,7 @@ pub usingnamespace switch (native_arch) {...@@ -24,6 +24,7 @@ pub usingnamespace switch (native_arch) {
24 .x86_64 => @import("linux/x86_64.zig"),24 .x86_64 => @import("linux/x86_64.zig"),
25 .aarch64 => @import("linux/arm64.zig"),25 .aarch64 => @import("linux/arm64.zig"),
26 .arm => @import("linux/arm-eabi.zig"),26 .arm => @import("linux/arm-eabi.zig"),
27 .thumb => @import("linux/thumb.zig"),
27 .riscv64 => @import("linux/riscv64.zig"),28 .riscv64 => @import("linux/riscv64.zig"),
28 .sparcv9 => @import("linux/sparc64.zig"),29 .sparcv9 => @import("linux/sparc64.zig"),
29 .mips, .mipsel => @import("linux/mips.zig"),30 .mips, .mipsel => @import("linux/mips.zig"),
lib/std/os/linux/thumb.zig created+168
...@@ -0,0 +1,168 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6usingnamespace @import("../bits.zig");
7
8// The syscall interface is identical to the ARM one but we're facing an extra
9// challenge: r7, the register where the syscall number is stored, may be
10// reserved for the frame pointer.
11// Save and restore r7 around the syscall without touching the stack pointer not
12// to break the frame chain.
13
14pub fn syscall0(number: SYS) usize {
15 @setRuntimeSafety(false);
16
17 var buf: [2]usize = .{ @enumToInt(number), undefined };
18 return asm volatile (
19 \\ str r7, [%[tmp], #4]
20 \\ ldr r7, [%[tmp]]
21 \\ svc #0
22 \\ ldr r7, [%[tmp], #4]
23 : [ret] "={r0}" (-> usize)
24 : [tmp] "{r1}" (buf)
25 : "memory"
26 );
27}
28
29pub fn syscall1(number: SYS, arg1: usize) usize {
30 @setRuntimeSafety(false);
31
32 var buf: [2]usize = .{ @enumToInt(number), undefined };
33 return asm volatile (
34 \\ str r7, [%[tmp], #4]
35 \\ ldr r7, [%[tmp]]
36 \\ svc #0
37 \\ ldr r7, [%[tmp], #4]
38 : [ret] "={r0}" (-> usize)
39 : [tmp] "{r1}" (buf),
40 [arg1] "{r0}" (arg1)
41 : "memory"
42 );
43}
44
45pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize {
46 @setRuntimeSafety(false);
47
48 var buf: [2]usize = .{ @enumToInt(number), undefined };
49 return asm volatile (
50 \\ str r7, [%[tmp], #4]
51 \\ ldr r7, [%[tmp]]
52 \\ svc #0
53 \\ ldr r7, [%[tmp], #4]
54 : [ret] "={r0}" (-> usize)
55 : [tmp] "{r2}" (buf),
56 [arg1] "{r0}" (arg1),
57 [arg2] "{r1}" (arg2)
58 : "memory"
59 );
60}
61
62pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize {
63 @setRuntimeSafety(false);
64
65 var buf: [2]usize = .{ @enumToInt(number), undefined };
66 return asm volatile (
67 \\ str r7, [%[tmp], #4]
68 \\ ldr r7, [%[tmp]]
69 \\ svc #0
70 \\ ldr r7, [%[tmp], #4]
71 : [ret] "={r0}" (-> usize)
72 : [tmp] "{r3}" (buf),
73 [arg1] "{r0}" (arg1),
74 [arg2] "{r1}" (arg2),
75 [arg3] "{r2}" (arg3)
76 : "memory"
77 );
78}
79
80pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
81 @setRuntimeSafety(false);
82
83 var buf: [2]usize = .{ @enumToInt(number), undefined };
84 return asm volatile (
85 \\ str r7, [%[tmp], #4]
86 \\ ldr r7, [%[tmp]]
87 \\ svc #0
88 \\ ldr r7, [%[tmp], #4]
89 : [ret] "={r0}" (-> usize)
90 : [tmp] "{r4}" (buf),
91 [arg1] "{r0}" (arg1),
92 [arg2] "{r1}" (arg2),
93 [arg3] "{r2}" (arg3),
94 [arg4] "{r3}" (arg4)
95 : "memory"
96 );
97}
98
99pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
100 @setRuntimeSafety(false);
101
102 var buf: [2]usize = .{ @enumToInt(number), undefined };
103 return asm volatile (
104 \\ str r7, [%[tmp], #4]
105 \\ ldr r7, [%[tmp]]
106 \\ svc #0
107 \\ ldr r7, [%[tmp], #4]
108 : [ret] "={r0}" (-> usize)
109 : [tmp] "{r5}" (buf),
110 [arg1] "{r0}" (arg1),
111 [arg2] "{r1}" (arg2),
112 [arg3] "{r2}" (arg3),
113 [arg4] "{r3}" (arg4),
114 [arg5] "{r4}" (arg5)
115 : "memory"
116 );
117}
118
119pub fn syscall6(
120 number: SYS,
121 arg1: usize,
122 arg2: usize,
123 arg3: usize,
124 arg4: usize,
125 arg5: usize,
126 arg6: usize,
127) usize {
128 @setRuntimeSafety(false);
129
130 var buf: [2]usize = .{ @enumToInt(number), undefined };
131 return asm volatile (
132 \\ str r7, [%[tmp], #4]
133 \\ ldr r7, [%[tmp]]
134 \\ svc #0
135 \\ ldr r7, [%[tmp], #4]
136 : [ret] "={r0}" (-> usize)
137 : [tmp] "{r6}" (buf),
138 [arg1] "{r0}" (arg1),
139 [arg2] "{r1}" (arg2),
140 [arg3] "{r2}" (arg3),
141 [arg4] "{r3}" (arg4),
142 [arg5] "{r4}" (arg5),
143 [arg6] "{r5}" (arg6)
144 : "memory"
145 );
146}
147
148/// This matches the libc clone function.
149pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize;
150
151pub fn restore() callconv(.Naked) void {
152 return asm volatile (
153 \\ mov r7, %[number]
154 \\ svc #0
155 :
156 : [number] "I" (@enumToInt(SYS.sigreturn))
157 );
158}
159
160pub fn restore_rt() callconv(.Naked) void {
161 return asm volatile (
162 \\ mov r7, %[number]
163 \\ svc #0
164 :
165 : [number] "I" (@enumToInt(SYS.rt_sigreturn))
166 : "memory"
167 );
168}
lib/std/os/linux/tls.zig+3-3
...@@ -53,7 +53,7 @@ const TLSVariant = enum {...@@ -53,7 +53,7 @@ const TLSVariant = enum {
53};53};
5454
55const tls_variant = switch (native_arch) {55const tls_variant = switch (native_arch) {
56 .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,56 .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI,
57 .x86_64, .i386, .sparcv9 => TLSVariant.VariantII,57 .x86_64, .i386, .sparcv9 => TLSVariant.VariantII,
58 else => @compileError("undefined tls_variant for this architecture"),58 else => @compileError("undefined tls_variant for this architecture"),
59};59};
...@@ -62,7 +62,7 @@ const tls_variant = switch (native_arch) {...@@ -62,7 +62,7 @@ const tls_variant = switch (native_arch) {
62const tls_tcb_size = switch (native_arch) {62const tls_tcb_size = switch (native_arch) {
63 // ARM EABI mandates enough space for two pointers: the first one points to63 // ARM EABI mandates enough space for two pointers: the first one points to
64 // the DTV while the second one is unspecified but reserved64 // the DTV while the second one is unspecified but reserved
65 .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),65 .arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize),
66 // One pointer-sized word that points either to the DTV or the TCB itself66 // One pointer-sized word that points either to the DTV or the TCB itself
67 else => @sizeOf(usize),67 else => @sizeOf(usize),
68};68};
...@@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void {
150 : [addr] "r" (addr)150 : [addr] "r" (addr)
151 );151 );
152 },152 },
153 .arm => {153 .arm, .thumb => {
154 const rc = std.os.linux.syscall1(.set_tls, addr);154 const rc = std.os.linux.syscall1(.set_tls, addr);
155 assert(rc == 0);155 assert(rc == 0);
156 },156 },
lib/std/os/test.zig+2
...@@ -43,6 +43,8 @@ test "chdir smoke test" {...@@ -43,6 +43,8 @@ test "chdir smoke test" {
43 // Next, change current working directory to one level above43 // Next, change current working directory to one level above
44 const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute44 const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute
45 try os.chdir(parent);45 try os.chdir(parent);
46 // Restore cwd because process may have other tests that do not tolerate chdir.
47 defer os.chdir(old_cwd) catch unreachable;
46 var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;48 var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined;
47 const new_cwd = try os.getcwd(new_cwd_buf[0..]);49 const new_cwd = try os.getcwd(new_cwd_buf[0..]);
48 expect(mem.eql(u8, parent, new_cwd));50 expect(mem.eql(u8, parent, new_cwd));
lib/std/special/c.zig+1-1
...@@ -388,7 +388,7 @@ fn clone() callconv(.Naked) void {...@@ -388,7 +388,7 @@ fn clone() callconv(.Naked) void {
388 \\ svc #0388 \\ svc #0
389 );389 );
390 },390 },
391 .arm => {391 .arm, .thumb => {
392 // __clone(func, stack, flags, arg, ptid, tls, ctid)392 // __clone(func, stack, flags, arg, ptid, tls, ctid)
393 // r0, r1, r2, r3, +0, +4, +8393 // r0, r1, r2, r3, +0, +4, +8
394394
lib/std/special/compiler_rt/clzsi2.zig+20-7
...@@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 {...@@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 {
26}26}
2727
28fn __clzsi2_thumb1() callconv(.Naked) void {28fn __clzsi2_thumb1() callconv(.Naked) void {
29 @setRuntimeSafety(false);
30
29 // Similar to the generic version with the last two rounds replaced by a LUT31 // Similar to the generic version with the last two rounds replaced by a LUT
30 asm volatile (32 asm volatile (
31 \\ movs r1, #3233 \\ movs r1, #32
...@@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void {...@@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void {
58}60}
5961
60fn __clzsi2_arm32() callconv(.Naked) void {62fn __clzsi2_arm32() callconv(.Naked) void {
63 @setRuntimeSafety(false);
64
61 asm volatile (65 asm volatile (
62 \\ // Assumption: n != 066 \\ // Assumption: n != 0
63 \\ // r0: n67 \\ // r0: n
...@@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void {...@@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void {
104 unreachable;108 unreachable;
105}109}
106110
107pub const __clzsi2 = switch (std.Target.current.cpu.arch) {111pub const __clzsi2 = impl: {
108 .arm, .armeb => if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm))112 switch (std.Target.current.cpu.arch) {
109 __clzsi2_thumb1113 .arm, .armeb, .thumb, .thumbeb => {
110 else114 const use_thumb1 =
111 __clzsi2_arm32,115 (std.Target.current.cpu.arch.isThumb() or
112 .thumb, .thumbeb => __clzsi2_thumb1,116 std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm)) and
113 else => __clzsi2_generic,117 !std.Target.arm.featureSetHas(std.Target.current.cpu.features, .thumb2);
118
119 if (use_thumb1) break :impl __clzsi2_thumb1
120 // From here on we're either targeting Thumb2 or ARM.
121 else if (!std.Target.current.cpu.arch.isThumb()) break :impl __clzsi2_arm32
122 // Use the generic implementation otherwise.
123 else break :impl __clzsi2_generic;
124 },
125 else => break :impl __clzsi2_generic,
126 }
114};127};
115128
116test "test clzsi2" {129test "test clzsi2" {
lib/std/special/compiler_rt/clzsi2_test.zig+2
...@@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig");...@@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig");
7const testing = @import("std").testing;7const testing = @import("std").testing;
88
9fn test__clzsi2(a: u32, expected: i32) void {9fn test__clzsi2(a: u32, expected: i32) void {
10 // XXX At high optimization levels this test may be horribly miscompiled if
11 // one of the naked implementations is selected.
10 var nakedClzsi2 = clzsi2.__clzsi2;12 var nakedClzsi2 = clzsi2.__clzsi2;
11 var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);13 var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2);
12 var x = @bitCast(i32, a);14 var x = @bitCast(i32, a);
lib/std/start.zig+1-1
...@@ -182,7 +182,7 @@ fn _start() callconv(.Naked) noreturn {...@@ -182,7 +182,7 @@ fn _start() callconv(.Naked) noreturn {
182 : [argc] "={esp}" (-> [*]usize)182 : [argc] "={esp}" (-> [*]usize)
183 );183 );
184 },184 },
185 .aarch64, .aarch64_be, .arm, .armeb => {185 .aarch64, .aarch64_be, .arm, .armeb, .thumb => {
186 argc_argv_ptr = asm volatile (186 argc_argv_ptr = asm volatile (
187 \\ mov fp, #0187 \\ mov fp, #0
188 \\ mov lr, #0188 \\ mov lr, #0
lib/std/zig/system.zig+9
...@@ -350,6 +350,15 @@ pub const NativeTargetInfo = struct {...@@ -350,6 +350,15 @@ pub const NativeTargetInfo = struct {
350 }350 }
351 }351 }
352 },352 },
353 .arm, .armeb => {
354 // XXX What do we do if the target has the noarm feature?
355 // What do we do if the user specifies +thumb_mode?
356 },
357 .thumb, .thumbeb => {
358 result.target.cpu.features.addFeature(
359 @enumToInt(std.Target.arm.Feature.thumb_mode),
360 );
361 },
353 else => {},362 else => {},
354 }363 }
355 cross_target.updateCpuFeatures(&result.target.cpu.features);364 cross_target.updateCpuFeatures(&result.target.cpu.features);
src/link/MachO/Archive.zig+6-3
...@@ -16,7 +16,7 @@ allocator: *Allocator,...@@ -16,7 +16,7 @@ allocator: *Allocator,
16arch: ?std.Target.Cpu.Arch = null,16arch: ?std.Target.Cpu.Arch = null,
17file: ?fs.File = null,17file: ?fs.File = null,
18header: ?ar_hdr = null,18header: ?ar_hdr = null,
19name: ?[]u8 = null,19name: ?[]const u8 = null,
2020
21/// Parsed table of contents.21/// Parsed table of contents.
22/// Each symbol name points to a list of all definition22/// Each symbol name points to a list of all definition
...@@ -195,7 +195,7 @@ fn parseTableOfContents(self: *Archive, reader: anytype) !void {...@@ -195,7 +195,7 @@ fn parseTableOfContents(self: *Archive, reader: anytype) !void {
195}195}
196196
197/// Caller owns the Object instance.197/// Caller owns the Object instance.
198pub fn parseObject(self: Archive, offset: u32) !Object {198pub fn parseObject(self: Archive, offset: u32) !*Object {
199 var reader = self.file.?.reader();199 var reader = self.file.?.reader();
200 try reader.context.seekTo(offset);200 try reader.context.seekTo(offset);
201201
...@@ -217,7 +217,10 @@ pub fn parseObject(self: Archive, offset: u32) !Object {...@@ -217,7 +217,10 @@ pub fn parseObject(self: Archive, offset: u32) !Object {
217 break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_name });217 break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_name });
218 };218 };
219219
220 var object = Object.init(self.allocator);220 var object = try self.allocator.create(Object);
221 errdefer self.allocator.destroy(object);
222
223 object.* = Object.init(self.allocator);
221 object.arch = self.arch.?;224 object.arch = self.arch.?;
222 object.file = try fs.cwd().openFile(self.name.?, .{});225 object.file = try fs.cwd().openFile(self.name.?, .{});
223 object.name = name;226 object.name = name;
src/link/MachO/Object.zig+21-5
...@@ -22,7 +22,7 @@ arch: ?std.Target.Cpu.Arch = null,...@@ -22,7 +22,7 @@ arch: ?std.Target.Cpu.Arch = null,
22header: ?macho.mach_header_64 = null,22header: ?macho.mach_header_64 = null,
23file: ?fs.File = null,23file: ?fs.File = null,
24file_offset: ?u32 = null,24file_offset: ?u32 = null,
25name: ?[]u8 = null,25name: ?[]const u8 = null,
2626
27load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},27load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
28sections: std.ArrayListUnmanaged(Section) = .{},28sections: std.ArrayListUnmanaged(Section) = .{},
...@@ -343,14 +343,22 @@ pub fn parseSymbols(self: *Object) !void {...@@ -343,14 +343,22 @@ pub fn parseSymbols(self: *Object) !void {
343 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);343 _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff);
344344
345 for (slice) |sym| {345 for (slice) |sym| {
346 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
347
346 if (Symbol.isStab(sym)) {348 if (Symbol.isStab(sym)) {
347 log.err("TODO handle stabs embedded within object files", .{});349 log.err("stab {s} in {s}", .{ sym_name, self.name.? });
348 return error.HandleStabsInObjects;350 return error.UnhandledSymbolType;
351 }
352 if (Symbol.isIndr(sym)) {
353 log.err("indirect symbol {s} in {s}", .{ sym_name, self.name.? });
354 return error.UnhandledSymbolType;
355 }
356 if (Symbol.isAbs(sym)) {
357 log.err("absolute symbol {s} in {s}", .{ sym_name, self.name.? });
358 return error.UnhandledSymbolType;
349 }359 }
350360
351 const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx));
352 const name = try self.allocator.dupe(u8, sym_name);361 const name = try self.allocator.dupe(u8, sym_name);
353
354 const symbol: *Symbol = symbol: {362 const symbol: *Symbol = symbol: {
355 if (Symbol.isSect(sym)) {363 if (Symbol.isSect(sym)) {
356 const linkage: Symbol.Regular.Linkage = linkage: {364 const linkage: Symbol.Regular.Linkage = linkage: {
...@@ -374,6 +382,14 @@ pub fn parseSymbols(self: *Object) !void {...@@ -374,6 +382,14 @@ pub fn parseSymbols(self: *Object) !void {
374 break :symbol &regular.base;382 break :symbol &regular.base;
375 }383 }
376384
385 if (sym.n_value != 0) {
386 log.err("common symbol {s} in {s}", .{ sym_name, self.name.? });
387 return error.UnhandledSymbolType;
388 // const comm_size = sym.n_value;
389 // const comm_align = (sym.n_desc >> 8) & 0x0f;
390 // log.warn("Common symbol: size 0x{x}, align 0x{x}", .{ comm_size, comm_align });
391 }
392
377 const undef = try self.allocator.create(Symbol.Unresolved);393 const undef = try self.allocator.create(Symbol.Unresolved);
378 errdefer self.allocator.destroy(undef);394 errdefer self.allocator.destroy(undef);
379 undef.* = .{395 undef.* = .{
src/link/MachO/Symbol.zig+10
...@@ -133,6 +133,16 @@ pub fn isUndf(sym: macho.nlist_64) bool {...@@ -133,6 +133,16 @@ pub fn isUndf(sym: macho.nlist_64) bool {
133 return type_ == macho.N_UNDF;133 return type_ == macho.N_UNDF;
134}134}
135135
136pub fn isIndr(sym: macho.nlist_64) bool {
137 const type_ = macho.N_TYPE & sym.n_type;
138 return type_ == macho.N_INDR;
139}
140
141pub fn isAbs(sym: macho.nlist_64) bool {
142 const type_ = macho.N_TYPE & sym.n_type;
143 return type_ == macho.N_ABS;
144}
145
136pub fn isWeakDef(sym: macho.nlist_64) bool {146pub fn isWeakDef(sym: macho.nlist_64) bool {
137 return (sym.n_desc & macho.N_WEAK_DEF) != 0;147 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
138}148}
src/link/MachO/Zld.zig+21-10
...@@ -82,7 +82,7 @@ unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},...@@ -82,7 +82,7 @@ unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
82strtab: std.ArrayListUnmanaged(u8) = .{},82strtab: std.ArrayListUnmanaged(u8) = .{},
83strtab_dir: std.StringHashMapUnmanaged(u32) = .{},83strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
8484
85threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},85threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
86local_rebases: std.ArrayListUnmanaged(Pointer) = .{},86local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
87stubs: std.ArrayListUnmanaged(*Symbol) = .{},87stubs: std.ArrayListUnmanaged(*Symbol) = .{},
88got_entries: std.ArrayListUnmanaged(*Symbol) = .{},88got_entries: std.ArrayListUnmanaged(*Symbol) = .{},
...@@ -92,6 +92,15 @@ stub_helper_stubs_start_off: ?u64 = null,...@@ -92,6 +92,15 @@ stub_helper_stubs_start_off: ?u64 = null,
92mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},92mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
93unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},93unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
9494
95const TlvOffset = struct {
96 source_addr: u64,
97 offset: u64,
98
99 fn cmp(context: void, a: TlvOffset, b: TlvOffset) bool {
100 return a.source_addr < b.source_addr;
101 }
102};
103
95const MappingKey = struct {104const MappingKey = struct {
96 object_id: u16,105 object_id: u16,
97 source_sect_id: u16,106 source_sect_id: u16,
...@@ -277,7 +286,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -277,7 +286,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
277286
278 object.* = Object.init(self.allocator);287 object.* = Object.init(self.allocator);
279 object.arch = self.arch.?;288 object.arch = self.arch.?;
280 object.name = try self.allocator.dupe(u8, input.name);289 object.name = input.name;
281 object.file = input.file;290 object.file = input.file;
282 try object.parse();291 try object.parse();
283 try self.objects.append(self.allocator, object);292 try self.objects.append(self.allocator, object);
...@@ -288,7 +297,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {...@@ -288,7 +297,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void {
288297
289 archive.* = Archive.init(self.allocator);298 archive.* = Archive.init(self.allocator);
290 archive.arch = self.arch.?;299 archive.arch = self.arch.?;
291 archive.name = try self.allocator.dupe(u8, input.name);300 archive.name = input.name;
292 archive.file = input.file;301 archive.file = input.file;
293 try archive.parse();302 try archive.parse();
294 try self.archives.append(self.allocator, archive);303 try self.archives.append(self.allocator, archive);
...@@ -1362,10 +1371,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1362,10 +1371,7 @@ fn resolveSymbols(self: *Zld) !void {
1362 };1371 };
1363 assert(offsets.items.len > 0);1372 assert(offsets.items.len > 0);
13641373
1365 const object = try self.allocator.create(Object);1374 const object = try archive.parseObject(offsets.items[0]);
1366 errdefer self.allocator.destroy(object);
1367
1368 object.* = try archive.parseObject(offsets.items[0]);
1369 try self.objects.append(self.allocator, object);1375 try self.objects.append(self.allocator, object);
1370 try self.resolveSymbolsInObject(object);1376 try self.resolveSymbolsInObject(object);
13711377
...@@ -1567,7 +1573,10 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1567,7 +1573,10 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1567 };1573 };
1568 // Since we require TLV data to always preceed TLV bss section, we calculate1574 // Since we require TLV data to always preceed TLV bss section, we calculate
1569 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.1575 // offsets wrt to the former if it is defined; otherwise, wrt to the latter.
1570 try self.threadlocal_offsets.append(self.allocator, args.target_addr - base_addr);1576 try self.threadlocal_offsets.append(self.allocator, .{
1577 .source_addr = args.source_addr,
1578 .offset = args.target_addr - base_addr,
1579 });
1571 }1580 }
1572 },1581 },
1573 .got_page, .got_page_off, .got_load, .got => {1582 .got_page, .got_page_off, .got_load, .got => {
...@@ -2093,10 +2102,12 @@ fn flush(self: *Zld) !void {...@@ -2093,10 +2102,12 @@ fn flush(self: *Zld) !void {
2093 var stream = std.io.fixedBufferStream(buffer);2102 var stream = std.io.fixedBufferStream(buffer);
2094 var writer = stream.writer();2103 var writer = stream.writer();
20952104
2105 std.sort.sort(TlvOffset, self.threadlocal_offsets.items, {}, TlvOffset.cmp);
2106
2096 const seek_amt = 2 * @sizeOf(u64);2107 const seek_amt = 2 * @sizeOf(u64);
2097 while (self.threadlocal_offsets.popOrNull()) |offset| {2108 for (self.threadlocal_offsets.items) |tlv| {
2098 try writer.context.seekBy(seek_amt);2109 try writer.context.seekBy(seek_amt);
2099 try writer.writeIntLittle(u64, offset);2110 try writer.writeIntLittle(u64, tlv.offset);
2100 }2111 }
21012112
2102 try self.file.?.pwriteAll(buffer, sect.offset);2113 try self.file.?.pwriteAll(buffer, sect.offset);
src/link/MachO/reloc/aarch64.zig+1-1
...@@ -25,7 +25,7 @@ pub const Branch = struct {...@@ -25,7 +25,7 @@ pub const Branch = struct {
25 log.debug(" | displacement 0x{x}", .{displacement});25 log.debug(" | displacement 0x{x}", .{displacement});
2626
27 var inst = branch.inst;27 var inst = branch.inst;
28 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement) >> 2);28 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
29 mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32());29 mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32());
30 }30 }
31};31};
src/stage1/codegen.cpp+3-1
...@@ -4880,6 +4880,9 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I...@@ -4880,6 +4880,9 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I
4880 type_ref = get_llvm_type(g, wider_type);4880 type_ref = get_llvm_type(g, wider_type);
4881 value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref);4881 value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref);
4882 }4882 }
4883 } else if (handle_is_ptr(g, type)) {
4884 ZigType *gen_type = get_pointer_to_type(g, type, true);
4885 type_ref = get_llvm_type(g, gen_type);
4883 }4886 }
48844887
4885 param_types[param_index] = type_ref;4888 param_types[param_index] = type_ref;
...@@ -9302,7 +9305,6 @@ static void init(CodeGen *g) {...@@ -9302,7 +9305,6 @@ static void init(CodeGen *g) {
9302 char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref);9305 char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref);
9303 LLVMSetDataLayout(g->module, layout_str);9306 LLVMSetDataLayout(g->module, layout_str);
93049307
9305
9306 assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref));9308 assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref));
9307 g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian);9309 g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian);
93089310
src/stage1/parser.cpp+10-1
...@@ -825,7 +825,16 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {...@@ -825,7 +825,16 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
825 AstNode *return_type = nullptr;825 AstNode *return_type = nullptr;
826 if (anytype == nullptr) {826 if (anytype == nullptr) {
827 exmark = eat_token_if(pc, TokenIdBang);827 exmark = eat_token_if(pc, TokenIdBang);
828 return_type = ast_expect(pc, ast_parse_type_expr);828 return_type = ast_parse_type_expr(pc);
829 if (return_type == nullptr) {
830 Token *next = peek_token(pc);
831 ast_error(
832 pc,
833 next,
834 "expected return type (use 'void' to return nothing), found: '%s'",
835 token_name(next->id)
836 );
837 }
829 }838 }
830839
831 AstNode *res = ast_create_node(pc, NodeTypeFnProto, first);840 AstNode *res = ast_create_node(pc, NodeTypeFnProto, first);
test/behavior/align.zig+3
...@@ -142,6 +142,7 @@ fn alignedBig() align(16) i32 {...@@ -142,6 +142,7 @@ fn alignedBig() align(16) i32 {
142test "@alignCast functions" {142test "@alignCast functions" {
143 // function alignment is a compile error on wasm32/wasm64143 // function alignment is a compile error on wasm32/wasm64
144 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;144 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
145 if (native_arch == .thumb) return error.SkipZigTest;
145146
146 expect(fnExpectsOnly1(simple4) == 0x19);147 expect(fnExpectsOnly1(simple4) == 0x19);
147}148}
...@@ -158,6 +159,7 @@ fn simple4() align(4) i32 {...@@ -158,6 +159,7 @@ fn simple4() align(4) i32 {
158test "generic function with align param" {159test "generic function with align param" {
159 // function alignment is a compile error on wasm32/wasm64160 // function alignment is a compile error on wasm32/wasm64
160 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;161 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
162 if (native_arch == .thumb) return error.SkipZigTest;
161163
162 expect(whyWouldYouEverDoThis(1) == 0x1);164 expect(whyWouldYouEverDoThis(1) == 0x1);
163 expect(whyWouldYouEverDoThis(4) == 0x1);165 expect(whyWouldYouEverDoThis(4) == 0x1);
...@@ -339,6 +341,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {...@@ -339,6 +341,7 @@ test "align(@alignOf(T)) T does not force resolution of T" {
339test "align(N) on functions" {341test "align(N) on functions" {
340 // function alignment is a compile error on wasm32/wasm64342 // function alignment is a compile error on wasm32/wasm64
341 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;343 if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest;
344 if (native_arch == .thumb) return error.SkipZigTest;
342345
343 expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0);346 expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0);
344}347}
test/behavior/asm.zig+15
...@@ -87,6 +87,21 @@ test "sized integer/float in asm input" {...@@ -87,6 +87,21 @@ test "sized integer/float in asm input" {
87 );87 );
88}88}
8989
90test "struct/array/union types as input values" {
91 asm volatile (""
92 :
93 : [_] "m" (@as([1]u32, undefined))
94 ); // fails
95 asm volatile (""
96 :
97 : [_] "m" (@as(struct { x: u32, y: u8 }, undefined))
98 ); // fails
99 asm volatile (""
100 :
101 : [_] "m" (@as(union { x: u32, y: u8 }, undefined))
102 ); // fails
103}
104
90extern fn this_is_my_alias() i32;105extern fn this_is_my_alias() i32;
91106
92export fn derp() i32 {107export fn derp() i32 {
test/behavior/async_fn.zig+4-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;2const builtin = @import("builtin");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const expectEqual = std.testing.expectEqual;4const expectEqual = std.testing.expectEqual;
5const expectEqualStrings = std.testing.expectEqualStrings;5const expectEqualStrings = std.testing.expectEqualStrings;
...@@ -110,6 +110,9 @@ test "calling an inferred async function" {...@@ -110,6 +110,9 @@ test "calling an inferred async function" {
110}110}
111111
112test "@frameSize" {112test "@frameSize" {
113 if (builtin.target.cpu.arch == .thumb or builtin.target.cpu.arch == .thumbeb)
114 return error.SkipZigTest;
115
113 const S = struct {116 const S = struct {
114 fn doTheTest() void {117 fn doTheTest() void {
115 {118 {
test/behavior/atomics.zig+3-5
...@@ -149,12 +149,10 @@ fn testAtomicStore() void {...@@ -149,12 +149,10 @@ fn testAtomicStore() void {
149}149}
150150
151test "atomicrmw with floats" {151test "atomicrmw with floats" {
152 if (builtin.target.cpu.arch == .aarch64 or152 switch (builtin.target.cpu.arch) {
153 builtin.target.cpu.arch == .arm or
154 builtin.target.cpu.arch == .riscv64)
155 {
156 // https://github.com/ziglang/zig/issues/4457153 // https://github.com/ziglang/zig/issues/4457
157 return error.SkipZigTest;154 .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest,
155 else => {},
158 }156 }
159 testAtomicRmwFloat();157 testAtomicRmwFloat();
160 comptime testAtomicRmwFloat();158 comptime testAtomicRmwFloat();
test/behavior/vector.zig-15
...@@ -510,21 +510,6 @@ test "vector reduce operation" {...@@ -510,21 +510,6 @@ test "vector reduce operation" {
510 const N = @typeInfo(@TypeOf(x)).Array.len;510 const N = @typeInfo(@TypeOf(x)).Array.len;
511 const TX = @typeInfo(@TypeOf(x)).Array.child;511 const TX = @typeInfo(@TypeOf(x)).Array.child;
512512
513 // wasmtime: unknown import: `env::fminf` has not been defined
514 // https://github.com/ziglang/zig/issues/8131
515 switch (builtin.target.cpu.arch) {
516 .wasm32 => switch (@typeInfo(TX)) {
517 .Float => switch (op) {
518 .Min,
519 .Max,
520 => return,
521 else => {},
522 },
523 else => {},
524 },
525 else => {},
526 }
527
528 var r = @reduce(op, @as(Vector(N, TX), x));513 var r = @reduce(op, @as(Vector(N, TX), x));
529 switch (@typeInfo(TX)) {514 switch (@typeInfo(TX)) {
530 .Int, .Bool => expectEqual(expected, r),515 .Int, .Bool => expectEqual(expected, r),