| author | |
| committer | |
| log | 91c3206b45074821749f52043937bf6ed6d9a105 |
| tree | 5d6d674d146e4189bc22865bed42dea0f9ada320 |
| parent | b521510cd4e68407226dd95c9e87cc97ca5a0796 |
This effectively allows us to compile
```zig
pub fn main() void {}
```
which then calls into `std.start`.
Changes required to make this happen:
* handle signed int to immediate in x86_64 and aarch64 codegen
* ensure that on arm64 macOS, `.x19` is a caller-preserved register -
I'm not sure about that one at all and would like to brainstorm it
with anyone interested and especially Joachim.
* finally, fix a bug in the linker - mark new got entry as dirty upon
atom growth.5 files changed, 40 insertions(+), 15 deletions(-)
src/arch/aarch64/CodeGen.zig+3| ... | @@ -2393,6 +2393,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -2393,6 +2393,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 2393 | }, | 2393 | }, |
| 2394 | .Int => { | 2394 | .Int => { |
| 2395 | const info = typed_value.ty.intInfo(self.target.*); | 2395 | const info = typed_value.ty.intInfo(self.target.*); |
| 2396 | if (info.bits <= ptr_bits and info.signedness == .signed) { | ||
| 2397 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; | ||
| 2398 | } | ||
| 2396 | if (info.bits > ptr_bits or info.signedness == .signed) { | 2399 | if (info.bits > ptr_bits or info.signedness == .signed) { |
| 2397 | return self.fail("TODO const int bigger than ptr and signed int", .{}); | 2400 | return self.fail("TODO const int bigger than ptr and signed int", .{}); |
| 2398 | } | 2401 | } |
src/arch/aarch64/bits.zig+13-3| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | ||
| 2 | const DW = std.dwarf; | 3 | const DW = std.dwarf; |
| 3 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 4 | const testing = std.testing; | 5 | const testing = std.testing; |
| ... | @@ -58,10 +59,19 @@ pub const Register = enum(u6) { | ... | @@ -58,10 +59,19 @@ pub const Register = enum(u6) { |
| 58 | 59 | ||
| 59 | // zig fmt: on | 60 | // zig fmt: on |
| 60 | 61 | ||
| 61 | pub const callee_preserved_regs = [_]Register{ | 62 | const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct { |
| 62 | .x19, .x20, .x21, .x22, .x23, | 63 | pub const callee_preserved_regs = [_]Register{ |
| 63 | .x24, .x25, .x26, .x27, .x28, | 64 | .x20, .x21, .x22, .x23, |
| 65 | .x24, .x25, .x26, .x27, | ||
| 66 | .x28, | ||
| 67 | }; | ||
| 68 | } else struct { | ||
| 69 | pub const callee_preserved_regs = [_]Register{ | ||
| 70 | .x19, .x20, .x21, .x22, .x23, | ||
| 71 | .x24, .x25, .x26, .x27, .x28, | ||
| 72 | }; | ||
| 64 | }; | 73 | }; |
| 74 | pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_regs; | ||
| 65 | 75 | ||
| 66 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | 76 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; |
| 67 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | 77 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; |
src/arch/x86_64/CodeGen.zig+3| ... | @@ -3178,6 +3178,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | ... | @@ -3178,6 +3178,9 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 3178 | }, | 3178 | }, |
| 3179 | .Int => { | 3179 | .Int => { |
| 3180 | const info = typed_value.ty.intInfo(self.target.*); | 3180 | const info = typed_value.ty.intInfo(self.target.*); |
| 3181 | if (info.bits <= ptr_bits and info.signedness == .signed) { | ||
| 3182 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt()) }; | ||
| 3183 | } | ||
| 3181 | if (info.bits > ptr_bits or info.signedness == .signed) { | 3184 | if (info.bits > ptr_bits or info.signedness == .signed) { |
| 3182 | return self.fail("TODO const int bigger than ptr and signed int", .{}); | 3185 | return self.fail("TODO const int bigger than ptr and signed int", .{}); |
| 3183 | } | 3186 | } |
src/link/MachO.zig+1| ... | @@ -3285,6 +3285,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 | ... | @@ -3285,6 +3285,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64 |
| 3285 | .seg = self.data_const_segment_cmd_index.?, | 3285 | .seg = self.data_const_segment_cmd_index.?, |
| 3286 | .sect = self.got_section_index.?, | 3286 | .sect = self.got_section_index.?, |
| 3287 | }).? + 1); | 3287 | }).? + 1); |
| 3288 | got_atom.dirty = true; | ||
| 3288 | } | 3289 | } |
| 3289 | 3290 | ||
| 3290 | symbol.n_value = vaddr; | 3291 | symbol.n_value = vaddr; |
test/stage2/darwin.zig+20-12| ... | @@ -45,18 +45,32 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -45,18 +45,32 @@ pub fn addCases(ctx: *TestContext) !void { |
| 45 | "Hello, World!\n", | 45 | "Hello, World!\n", |
| 46 | ); | 46 | ); |
| 47 | 47 | ||
| 48 | // Now using start.zig without an explicit extern exit fn | ||
| 49 | case.addCompareOutput( | ||
| 50 | \\extern fn write(usize, usize, usize) usize; | ||
| 51 | \\ | ||
| 52 | \\pub fn main() void { | ||
| 53 | \\ print(); | ||
| 54 | \\} | ||
| 55 | \\ | ||
| 56 | \\fn print() void { | ||
| 57 | \\ const msg = @ptrToInt("Hello, World!\n"); | ||
| 58 | \\ const len = 14; | ||
| 59 | \\ _ = write(1, msg, len); | ||
| 60 | \\} | ||
| 61 | , | ||
| 62 | "Hello, World!\n", | ||
| 63 | ); | ||
| 64 | |||
| 48 | // Print it 4 times and force growth and realloc. | 65 | // Print it 4 times and force growth and realloc. |
| 49 | case.addCompareOutput( | 66 | case.addCompareOutput( |
| 50 | \\extern fn write(usize, usize, usize) usize; | 67 | \\extern fn write(usize, usize, usize) usize; |
| 51 | \\extern fn exit(usize) noreturn; | ||
| 52 | \\ | 68 | \\ |
| 53 | \\pub export fn main() noreturn { | 69 | \\pub fn main() void { |
| 54 | \\ print(); | 70 | \\ print(); |
| 55 | \\ print(); | 71 | \\ print(); |
| 56 | \\ print(); | 72 | \\ print(); |
| 57 | \\ print(); | 73 | \\ print(); |
| 58 | \\ | ||
| 59 | \\ exit(0); | ||
| 60 | \\} | 74 | \\} |
| 61 | \\ | 75 | \\ |
| 62 | \\fn print() void { | 76 | \\fn print() void { |
| ... | @@ -75,12 +89,9 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -75,12 +89,9 @@ pub fn addCases(ctx: *TestContext) !void { |
| 75 | // Print it once, and change the message. | 89 | // Print it once, and change the message. |
| 76 | case.addCompareOutput( | 90 | case.addCompareOutput( |
| 77 | \\extern fn write(usize, usize, usize) usize; | 91 | \\extern fn write(usize, usize, usize) usize; |
| 78 | \\extern fn exit(usize) noreturn; | ||
| 79 | \\ | 92 | \\ |
| 80 | \\pub export fn main() noreturn { | 93 | \\pub fn main() void { |
| 81 | \\ print(); | 94 | \\ print(); |
| 82 | \\ | ||
| 83 | \\ exit(0); | ||
| 84 | \\} | 95 | \\} |
| 85 | \\ | 96 | \\ |
| 86 | \\fn print() void { | 97 | \\fn print() void { |
| ... | @@ -95,13 +106,10 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -95,13 +106,10 @@ pub fn addCases(ctx: *TestContext) !void { |
| 95 | // Now we print it twice. | 106 | // Now we print it twice. |
| 96 | case.addCompareOutput( | 107 | case.addCompareOutput( |
| 97 | \\extern fn write(usize, usize, usize) usize; | 108 | \\extern fn write(usize, usize, usize) usize; |
| 98 | \\extern fn exit(usize) noreturn; | ||
| 99 | \\ | 109 | \\ |
| 100 | \\pub export fn main() noreturn { | 110 | \\pub fn main() void { |
| 101 | \\ print(); | 111 | \\ print(); |
| 102 | \\ print(); | 112 | \\ print(); |
| 103 | \\ | ||
| 104 | \\ exit(0); | ||
| 105 | \\} | 113 | \\} |
| 106 | \\ | 114 | \\ |
| 107 | \\fn print() void { | 115 | \\fn print() void { |