| author | |
| committer | |
| log | 55811d8dac9109aa6357639908fb4f6c479480f9 |
| tree | 668f796e1c6feeb6972f178c4a9c1333c594cdce |
| parent | 609207801a570508e58d9e02b6ce551fbf1dca30 |
Clang has a completely inconsistent CLI for its integrated assembler for
each target architecture. For x86_64, for example, it does not accept
an -mcpu parameter, and emits "warning: unused parameter". However, for
ARM, -mcpu is needed in order to properly lower assembly to machine code
instructions (see new standalone test case provided thanks to @g-w1).
This is a compromise between
b8f85a805bf61ae11d6ee2bd6d8356fbc98ee3ba and
afb9f695b1bdbf81185e7d55d5783bcbab880989.7 files changed, 139 insertions(+), 15 deletions(-)
src/Compilation.zig+27-15| ... | @@ -2943,26 +2943,38 @@ pub fn addCCArgs( | ... | @@ -2943,26 +2943,38 @@ pub fn addCCArgs( |
| 2943 | try argv.append("-fPIC"); | 2943 | try argv.append("-fPIC"); |
| 2944 | } | 2944 | } |
| 2945 | }, | 2945 | }, |
| 2946 | .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {}, | 2946 | .shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {}, |
| 2947 | .assembly => { | ||
| 2948 | // The Clang assembler does not accept the list of CPU features like the | ||
| 2949 | // compiler frontend does. Therefore we must hard-code the -m flags for | ||
| 2950 | // all CPU features here. | ||
| 2951 | switch (target.cpu.arch) { | ||
| 2952 | .riscv32, .riscv64 => { | ||
| 2953 | if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) { | ||
| 2954 | try argv.append("-mrelax"); | ||
| 2955 | } else { | ||
| 2956 | try argv.append("-mno-relax"); | ||
| 2957 | } | ||
| 2958 | }, | ||
| 2959 | else => { | ||
| 2960 | // TODO | ||
| 2961 | }, | ||
| 2962 | } | ||
| 2963 | if (target_util.clangAssemblerSupportsMcpuArg(target)) { | ||
| 2964 | if (target.cpu.model.llvm_name) |llvm_name| { | ||
| 2965 | try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name})); | ||
| 2966 | } | ||
| 2967 | } | ||
| 2968 | }, | ||
| 2947 | } | 2969 | } |
| 2948 | if (out_dep_path) |p| { | 2970 | if (out_dep_path) |p| { |
| 2949 | try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); | 2971 | try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p }); |
| 2950 | } | 2972 | } |
| 2951 | // Argh, why doesn't the assembler accept the list of CPU features?! | ||
| 2952 | // I don't see a way to do this other than hard coding everything. | ||
| 2953 | switch (target.cpu.arch) { | ||
| 2954 | .riscv32, .riscv64 => { | ||
| 2955 | if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) { | ||
| 2956 | try argv.append("-mrelax"); | ||
| 2957 | } else { | ||
| 2958 | try argv.append("-mno-relax"); | ||
| 2959 | } | ||
| 2960 | }, | ||
| 2961 | else => { | ||
| 2962 | // TODO | ||
| 2963 | }, | ||
| 2964 | } | ||
| 2965 | 2973 | ||
| 2974 | // We never want clang to invoke the system assembler for anything. So we would want | ||
| 2975 | // this option always enabled. However, it only matters for some targets. To avoid | ||
| 2976 | // "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this | ||
| 2977 | // flag on the command line if it is necessary. | ||
| 2966 | if (target_util.clangMightShellOutForAssembly(target)) { | 2978 | if (target_util.clangMightShellOutForAssembly(target)) { |
| 2967 | try argv.append("-integrated-as"); | 2979 | try argv.append("-integrated-as"); |
| 2968 | } | 2980 | } |
src/target.zig+9| ... | @@ -389,3 +389,12 @@ pub fn clangMightShellOutForAssembly(target: std.Target) bool { | ... | @@ -389,3 +389,12 @@ pub fn clangMightShellOutForAssembly(target: std.Target) bool { |
| 389 | // when targeting a non-BSD OS. | 389 | // when targeting a non-BSD OS. |
| 390 | return target.cpu.arch.isSPARC(); | 390 | return target.cpu.arch.isSPARC(); |
| 391 | } | 391 | } |
| 392 | |||
| 393 | /// Each backend architecture in Clang has a different codepath which may or may not | ||
| 394 | /// support an -mcpu flag. | ||
| 395 | pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool { | ||
| 396 | return switch (target.cpu.arch) { | ||
| 397 | .arm, .armeb, .thumb, .thumbeb => true, | ||
| 398 | else => false, | ||
| 399 | }; | ||
| 400 | } |
test/standalone.zig+1| ... | @@ -16,6 +16,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { | ... | @@ -16,6 +16,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void { |
| 16 | cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig"); | 16 | cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig"); |
| 17 | cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig"); | 17 | cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig"); |
| 18 | cases.addBuildFile("test/standalone/issue_339/build.zig"); | 18 | cases.addBuildFile("test/standalone/issue_339/build.zig"); |
| 19 | cases.addBuildFile("test/standalone/issue_8550/build.zig"); | ||
| 19 | cases.addBuildFile("test/standalone/issue_794/build.zig"); | 20 | cases.addBuildFile("test/standalone/issue_794/build.zig"); |
| 20 | cases.addBuildFile("test/standalone/issue_5825/build.zig"); | 21 | cases.addBuildFile("test/standalone/issue_5825/build.zig"); |
| 21 | cases.addBuildFile("test/standalone/pkg_import/build.zig"); | 22 | cases.addBuildFile("test/standalone/pkg_import/build.zig"); |
test/standalone/issue_8550/boot.S created+33| ... | @@ -0,0 +1,33 @@ | ||
| 1 | .section ".text.boot" | ||
| 2 | |||
| 3 | .global _start | ||
| 4 | |||
| 5 | _start: | ||
| 6 | mrc p15, #0, r1, c0, c0, #5 | ||
| 7 | and r1, r1, #3 | ||
| 8 | cmp r1, #0 | ||
| 9 | bne halt | ||
| 10 | |||
| 11 | mov sp, #0x8000 | ||
| 12 | |||
| 13 | ldr r4, =__bss_start | ||
| 14 | ldr r9, =__bss_end | ||
| 15 | mov r5, #0 | ||
| 16 | mov r6, #0 | ||
| 17 | mov r7, #0 | ||
| 18 | mov r8, #0 | ||
| 19 | b 2f | ||
| 20 | |||
| 21 | 1: | ||
| 22 | stmia r4!, {r5-r8} | ||
| 23 | |||
| 24 | 2: | ||
| 25 | cmp r4, r9 | ||
| 26 | blo 1b | ||
| 27 | |||
| 28 | ldr r3, =main | ||
| 29 | blx r3 | ||
| 30 | |||
| 31 | halt: | ||
| 32 | wfe | ||
| 33 | b halt | ||
test/standalone/issue_8550/build.zig created+21| ... | @@ -0,0 +1,21 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | |||
| 3 | pub fn build(b: *std.build.Builder) !void { | ||
| 4 | const target = std.zig.CrossTarget{ | ||
| 5 | .os_tag = .freestanding, | ||
| 6 | .cpu_arch = .arm, | ||
| 7 | .cpu_model = .{ | ||
| 8 | .explicit = &std.Target.arm.cpu.arm1176jz_s, | ||
| 9 | }, | ||
| 10 | }; | ||
| 11 | const mode = b.standardReleaseOptions(); | ||
| 12 | const kernel = b.addExecutable("kernel", "./main.zig"); | ||
| 13 | kernel.addObjectFile("./boot.S"); | ||
| 14 | kernel.setLinkerScriptPath("./linker.ld"); | ||
| 15 | kernel.setBuildMode(mode); | ||
| 16 | kernel.setTarget(target); | ||
| 17 | kernel.install(); | ||
| 18 | |||
| 19 | const test_step = b.step("test", "Test it"); | ||
| 20 | test_step.dependOn(&kernel.step); | ||
| 21 | } | ||
test/standalone/issue_8550/linker.ld created+42| ... | @@ -0,0 +1,42 @@ | ||
| 1 | ENTRY(_start) | ||
| 2 | |||
| 3 | SECTIONS | ||
| 4 | { | ||
| 5 | /* Starts at LOADER_ADDR. */ | ||
| 6 | . = 0x8000; | ||
| 7 | __start = .; | ||
| 8 | __text_start = .; | ||
| 9 | .text : | ||
| 10 | { | ||
| 11 | KEEP(*(.text.boot)) | ||
| 12 | *(.text) | ||
| 13 | } | ||
| 14 | . = ALIGN(4096); /* align to page size */ | ||
| 15 | __text_end = .; | ||
| 16 | |||
| 17 | __rodata_start = .; | ||
| 18 | .rodata : | ||
| 19 | { | ||
| 20 | *(.rodata) | ||
| 21 | } | ||
| 22 | . = ALIGN(4096); /* align to page size */ | ||
| 23 | __rodata_end = .; | ||
| 24 | |||
| 25 | __data_start = .; | ||
| 26 | .data : | ||
| 27 | { | ||
| 28 | *(.data) | ||
| 29 | } | ||
| 30 | . = ALIGN(4096); /* align to page size */ | ||
| 31 | __data_end = .; | ||
| 32 | |||
| 33 | __bss_start = .; | ||
| 34 | .bss : | ||
| 35 | { | ||
| 36 | bss = .; | ||
| 37 | *(.bss) | ||
| 38 | } | ||
| 39 | . = ALIGN(4096); /* align to page size */ | ||
| 40 | __bss_end = .; | ||
| 41 | __end = .; | ||
| 42 | } | ||
test/standalone/issue_8550/main.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | export fn main(r0: u32, r1: u32, atags: u32) callconv(.C) noreturn { | ||
| 2 | unreachable; // never gets run so it doesn't matter | ||
| 3 | } | ||
| 4 | pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace) noreturn { | ||
| 5 | while (true) {} | ||
| 6 | } | ||