From 0d4a5c40bc97d65ede1923577b2ca9dac3a6c24f Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Fri, 15 Mar 2019 20:16:42 +0100 Subject: [PATCH 1/7] correct padding handling between std.pdb.ModInfo entries in DbiStream --- std/debug.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/debug.zig b/std/debug.zig index b666e816af..0b5fc97f87 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -881,8 +881,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo { const obj_file_name = try dbi.readNullTermString(allocator); this_record_len += obj_file_name.len + 1; - const march_forward_bytes = this_record_len % 4; - if (march_forward_bytes != 0) { + if (this_record_len % 4 != 0) { + const round_to_next_4 = (this_record_len | 0x3) + 1; + const march_forward_bytes = round_to_next_4 - this_record_len; try dbi.seekForward(march_forward_bytes); this_record_len += march_forward_bytes; } From 094d40fb1a816a02e9f193f856049cf50503fdc4 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Fri, 15 Mar 2019 21:11:27 +0100 Subject: [PATCH 2/7] allow pdb modules to have no C13 data, this happens if the module is stripped --- std/debug.zig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/std/debug.zig b/std/debug.zig index 0b5fc97f87..2cd6f697d9 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -565,11 +565,12 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void { return; const allocator = getDebugInfoAllocator(); - if (mod.mod_info.C11ByteSize != 0) + // At most one can be non-zero. + if (mod.mod_info.C11ByteSize != 0 and mod.mod_info.C13ByteSize != 0) return error.InvalidDebugInfo; if (mod.mod_info.C13ByteSize == 0) - return error.MissingDebugInfo; + return; const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo; From 704dfaaabf2cf2253a6d58cc25f6cd8eff8c87bd Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Fri, 15 Mar 2019 21:44:12 +0100 Subject: [PATCH 3/7] avoid reading LineBlockFragmentHeader at all if the address is not in range, thus simplifying code and improving speed of execution --- std/debug.zig | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/std/debug.zig b/std/debug.zig index 2cd6f697d9..96b861e4a7 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -372,18 +372,20 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres const frag_vaddr_start = coff_section.header.virtual_address + line_hdr.RelocOffset; const frag_vaddr_end = frag_vaddr_start + line_hdr.CodeSize; - // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) - // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in, - // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection. - const subsection_end_index = sect_offset + subsect_hdr.Length; - while (line_index < subsection_end_index) { - const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]); - line_index += @sizeOf(pdb.LineBlockFragmentHeader); - const start_line_index = line_index; + if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) { + // There is an unknown number of LineBlockFragmentHeaders (and their accompanying line and column records) + // from now on. We will iterate through them, and eventually find a LineInfo that we're interested in, + // breaking out to :subsections. If not, we will make sure to not read anything outside of this subsection. - const has_column = line_hdr.Flags.LF_HaveColumns; + const subsection_end_index = sect_offset + subsect_hdr.Length; + + while (line_index < subsection_end_index) { + const block_hdr = @ptrCast(*pdb.LineBlockFragmentHeader, &subsect_info[line_index]); + line_index += @sizeOf(pdb.LineBlockFragmentHeader); + const start_line_index = line_index; + + const has_column = line_hdr.Flags.LF_HaveColumns; - if (relative_address >= frag_vaddr_start and relative_address < frag_vaddr_end) { // All line entries are stored inside their line block by ascending start address. // Heuristic: we want to find the last line entry that has a vaddr_start <= relative_address. // This is done with a simple linear search. @@ -427,11 +429,11 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres }; } } - } - // Checking that we are not reading garbage after the (possibly) multiple block fragments. - if (line_index != subsection_end_index) { - return error.InvalidDebugInfo; + // Checking that we are not reading garbage after the (possibly) multiple block fragments. + if (line_index != subsection_end_index) { + return error.InvalidDebugInfo; + } } }, else => {}, From ae9b90cf6ea1d3f214a9058be8e147911b745f00 Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Fri, 15 Mar 2019 21:45:38 +0100 Subject: [PATCH 4/7] print a message instead of returning an error when debug info comes from a source file not found (for example compiled on another computer) --- std/debug.zig | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/std/debug.zig b/std/debug.zig index 96b861e4a7..c85a982059 100644 --- a/std/debug.zig +++ b/std/debug.zig @@ -478,6 +478,11 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres } } else |err| switch (err) { error.EndOfFile => {}, + error.FileNotFound => { + setTtyColor(TtyColor.Dim); + try out_stream.write("file not found\n\n"); + setTtyColor(TtyColor.White); + }, else => return err, } } else { From c17b1635ca40488a0b0a804126d0bdd2212bdf6b Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 19 Mar 2019 22:08:19 +0100 Subject: [PATCH 5/7] c_abi: when compiling for x86_64, differenciate between system V and windows ABI --- src/analyze.cpp | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/analyze.cpp b/src/analyze.cpp index cadb5dfc01..c83327bbdf 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -6699,10 +6699,28 @@ Error file_fetch(CodeGen *g, Buf *resolved_path, Buf *contents) { } } -X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { - size_t ty_size = type_size(g, ty); - if (get_codegen_ptr_type(ty) != nullptr) - return X64CABIClass_INTEGER; +static X64CABIClass type_windows_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { + // https://docs.microsoft.com/en-gb/cpp/build/x64-calling-convention?view=vs-2017 + switch (ty->id) { + case ZigTypeIdEnum: + case ZigTypeIdInt: + case ZigTypeIdBool: + return X64CABIClass_INTEGER; + case ZigTypeIdFloat: + case ZigTypeIdVector: + return X64CABIClass_SSE; + case ZigTypeIdStruct: + case ZigTypeIdUnion: { + if (ty_size <= 8) + return X64CABIClass_INTEGER; + return X64CABIClass_MEMORY; + } + default: + return X64CABIClass_Unknown; + } +} + +static X64CABIClass type_system_V_abi_x86_64_class(CodeGen *g, ZigType *ty, size_t ty_size) { switch (ty->id) { case ZigTypeIdEnum: case ZigTypeIdInt: @@ -6770,6 +6788,18 @@ X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { } } +X64CABIClass type_c_abi_x86_64_class(CodeGen *g, ZigType *ty) { + const size_t ty_size = type_size(g, ty); + if (get_codegen_ptr_type(ty) != nullptr) + return X64CABIClass_INTEGER; + + if (g->zig_target->os == OsWindows || g->zig_target->os == OsUefi) { + return type_windows_abi_x86_64_class(g, ty, ty_size); + } else { + return type_system_V_abi_x86_64_class(g, ty, ty_size); + } +} + // NOTE this does not depend on x86_64 bool type_is_c_abi_int(CodeGen *g, ZigType *ty) { return (ty->id == ZigTypeIdInt || From 27d5e1f36cf7f7bd9345aba57d092206dc9e249b Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 19 Mar 2019 22:09:12 +0100 Subject: [PATCH 6/7] c_abi: add some tests for int and float parameter passing potentially using both registers and stack --- test/stage1/c_abi/cfuncs.c | 20 ++++++++++++++++++++ test/stage1/c_abi/main.zig | 24 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/test/stage1/c_abi/cfuncs.c b/test/stage1/c_abi/cfuncs.c index 102cd466b1..a26f8c98a1 100644 --- a/test/stage1/c_abi/cfuncs.c +++ b/test/stage1/c_abi/cfuncs.c @@ -18,9 +18,11 @@ void zig_i8(int8_t); void zig_i16(int16_t); void zig_i32(int32_t); void zig_i64(int64_t); +void zig_five_integers(int32_t, int32_t, int32_t, int32_t, int32_t); void zig_f32(float); void zig_f64(double); +void zig_five_floats(float, float, float, float, float); void zig_ptr(void *); @@ -71,9 +73,11 @@ void run_c_tests(void) { zig_i16(-2); zig_i32(-3); zig_i64(-4); + zig_five_integers(12, 34, 56, 78, 90); zig_f32(12.34f); zig_f64(56.78); + zig_five_floats(1.0f, 2.0f, 3.0f, 4.0f, 5.0f); zig_ptr((void*)0xdeadbeefL); @@ -156,6 +160,22 @@ void c_bool(bool x) { assert_or_panic(x); } +void c_five_integers(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e) { + assert_or_panic(a == 12); + assert_or_panic(b == 34); + assert_or_panic(c == 56); + assert_or_panic(d == 78); + assert_or_panic(e == 90); +} + +void c_five_floats(float a, float b, float c, float d, float e) { + assert_or_panic(a == 1.0); + assert_or_panic(b == 2.0); + assert_or_panic(c == 3.0); + assert_or_panic(d == 4.0); + assert_or_panic(e == 5.0); +} + void c_array(uint8_t x[10]) { assert_or_panic(x[0] == '1'); assert_or_panic(x[1] == '2'); diff --git a/test/stage1/c_abi/main.zig b/test/stage1/c_abi/main.zig index 4805fc9896..70688aa09c 100644 --- a/test/stage1/c_abi/main.zig +++ b/test/stage1/c_abi/main.zig @@ -20,6 +20,17 @@ extern fn c_i16(i16) void; extern fn c_i32(i32) void; extern fn c_i64(i64) void; +// On windows x64, the first 4 are passed via registers, others on the stack. +extern fn c_five_integers(i32, i32, i32, i32, i32) void; + +export fn zig_five_integers(a: i32, b: i32, c: i32, d: i32, e: i32) void { + expect(a == 12); + expect(b == 34); + expect(c == 56); + expect(d == 78); + expect(e == 90); +} + test "C ABI integers" { c_u8(0xff); c_u16(0xfffe); @@ -30,6 +41,7 @@ test "C ABI integers" { c_i16(-2); c_i32(-3); c_i64(-4); + c_five_integers(12, 34, 56, 78, 90); } export fn zig_u8(x: u8) void { @@ -60,9 +72,21 @@ export fn zig_i64(x: i64) void { extern fn c_f32(f32) void; extern fn c_f64(f64) void; +// On windows x64, the first 4 are passed via registers, others on the stack. +extern fn c_five_floats(f32, f32, f32, f32, f32) void; + +export fn zig_five_floats(a: f32, b: f32, c: f32, d: f32, e: f32) void { + expect(a == 1.0); + expect(b == 2.0); + expect(c == 3.0); + expect(d == 4.0); + expect(e == 5.0); +} + test "C ABI floats" { c_f32(12.34); c_f64(56.78); + c_five_floats(1.0, 2.0, 3.0, 4.0, 5.0); } export fn zig_f32(x: f32) void { From d669db76732a5137f9e37a22d08f5cba319a122d Mon Sep 17 00:00:00 2001 From: Sahnvour Date: Tue, 19 Mar 2019 22:41:27 +0100 Subject: [PATCH 7/7] c_abi: activate tests on windows --- test/build_examples.zig | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/build_examples.zig b/test/build_examples.zig index 33a288a108..c75c38b138 100644 --- a/test/build_examples.zig +++ b/test/build_examples.zig @@ -25,9 +25,7 @@ pub fn addCases(cases: *tests.BuildExamplesContext) void { cases.addBuildFile("test/standalone/load_dynamic_library/build.zig"); } - if (!is_windows // TODO support compiling C files on windows with zig build system - and builtin.arch == builtin.Arch.x86_64 // TODO add C ABI support for other architectures - ) { + if (builtin.arch == builtin.Arch.x86_64) { // TODO add C ABI support for other architectures cases.addBuildFile("test/stage1/c_abi/build.zig"); } }