stage2: introduce clangAssemblerSupportsMcpuArg

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.
This commit is contained in:
Andrew Kelley 2021-05-23 21:51:10 -07:00
parent 609207801a
commit 55811d8dac
7 changed files with 139 additions and 15 deletions

View File

@ -2943,26 +2943,38 @@ pub fn addCCArgs(
try argv.append("-fPIC");
}
},
.shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {},
.shared_library, .ll, .bc, .unknown, .static_library, .object, .zig => {},
.assembly => {
// The Clang assembler does not accept the list of CPU features like the
// compiler frontend does. Therefore we must hard-code the -m flags for
// all CPU features here.
switch (target.cpu.arch) {
.riscv32, .riscv64 => {
if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
try argv.append("-mrelax");
} else {
try argv.append("-mno-relax");
}
},
else => {
// TODO
},
}
if (target_util.clangAssemblerSupportsMcpuArg(target)) {
if (target.cpu.model.llvm_name) |llvm_name| {
try argv.append(try std.fmt.allocPrint(arena, "-mcpu={s}", .{llvm_name}));
}
}
},
}
if (out_dep_path) |p| {
try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
}
// Argh, why doesn't the assembler accept the list of CPU features?!
// I don't see a way to do this other than hard coding everything.
switch (target.cpu.arch) {
.riscv32, .riscv64 => {
if (std.Target.riscv.featureSetHas(target.cpu.features, .relax)) {
try argv.append("-mrelax");
} else {
try argv.append("-mno-relax");
}
},
else => {
// TODO
},
}
// We never want clang to invoke the system assembler for anything. So we would want
// this option always enabled. However, it only matters for some targets. To avoid
// "unused parameter" warnings, and to keep CLI spam to a minimum, we only put this
// flag on the command line if it is necessary.
if (target_util.clangMightShellOutForAssembly(target)) {
try argv.append("-integrated-as");
}

View File

@ -389,3 +389,12 @@ pub fn clangMightShellOutForAssembly(target: std.Target) bool {
// when targeting a non-BSD OS.
return target.cpu.arch.isSPARC();
}
/// Each backend architecture in Clang has a different codepath which may or may not
/// support an -mcpu flag.
pub fn clangAssemblerSupportsMcpuArg(target: std.Target) bool {
return switch (target.cpu.arch) {
.arm, .armeb, .thumb, .thumbeb => true,
else => false,
};
}

View File

@ -16,6 +16,7 @@ pub fn addCases(cases: *tests.StandaloneContext) void {
cases.addBuildFile("test/standalone/link_interdependent_static_c_libs/build.zig");
cases.addBuildFile("test/standalone/link_static_lib_as_system_lib/build.zig");
cases.addBuildFile("test/standalone/issue_339/build.zig");
cases.addBuildFile("test/standalone/issue_8550/build.zig");
cases.addBuildFile("test/standalone/issue_794/build.zig");
cases.addBuildFile("test/standalone/issue_5825/build.zig");
cases.addBuildFile("test/standalone/pkg_import/build.zig");

View File

@ -0,0 +1,33 @@
.section ".text.boot"
.global _start
_start:
mrc p15, #0, r1, c0, c0, #5
and r1, r1, #3
cmp r1, #0
bne halt
mov sp, #0x8000
ldr r4, =__bss_start
ldr r9, =__bss_end
mov r5, #0
mov r6, #0
mov r7, #0
mov r8, #0
b 2f
1:
stmia r4!, {r5-r8}
2:
cmp r4, r9
blo 1b
ldr r3, =main
blx r3
halt:
wfe
b halt

View File

@ -0,0 +1,21 @@
const std = @import("std");
pub fn build(b: *std.build.Builder) !void {
const target = std.zig.CrossTarget{
.os_tag = .freestanding,
.cpu_arch = .arm,
.cpu_model = .{
.explicit = &std.Target.arm.cpu.arm1176jz_s,
},
};
const mode = b.standardReleaseOptions();
const kernel = b.addExecutable("kernel", "./main.zig");
kernel.addObjectFile("./boot.S");
kernel.setLinkerScriptPath("./linker.ld");
kernel.setBuildMode(mode);
kernel.setTarget(target);
kernel.install();
const test_step = b.step("test", "Test it");
test_step.dependOn(&kernel.step);
}

View File

@ -0,0 +1,42 @@
ENTRY(_start)
SECTIONS
{
/* Starts at LOADER_ADDR. */
. = 0x8000;
__start = .;
__text_start = .;
.text :
{
KEEP(*(.text.boot))
*(.text)
}
. = ALIGN(4096); /* align to page size */
__text_end = .;
__rodata_start = .;
.rodata :
{
*(.rodata)
}
. = ALIGN(4096); /* align to page size */
__rodata_end = .;
__data_start = .;
.data :
{
*(.data)
}
. = ALIGN(4096); /* align to page size */
__data_end = .;
__bss_start = .;
.bss :
{
bss = .;
*(.bss)
}
. = ALIGN(4096); /* align to page size */
__bss_end = .;
__end = .;
}

View File

@ -0,0 +1,6 @@
export fn main(r0: u32, r1: u32, atags: u32) callconv(.C) noreturn {
unreachable; // never gets run so it doesn't matter
}
pub fn panic(msg: []const u8, error_return_trace: ?*@import("std").builtin.StackTrace) noreturn {
while (true) {}
}