authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-08-15 22:10:59-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-08-15 22:10:59-07:00
logb917d778c6e8fd24c420a18ecf3f55aab3f93798
treee95ea323f8b7a86db50fa9cd89ac3bf45d0d4df2
parent72bcc3b7a52a8ce7a582ed205325f761da72a6a5
parent7a8e86e46ceb1350509b4296c2a45af45100df41
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #21056 from alexrp/start-fix-precedence

`start`: Avoid string concatenation in inline asm.

2 files changed, 37 insertions(+), 45 deletions(-)

lib/std/start.zig+17-26
......@@ -232,6 +232,16 @@ fn _start() callconv(.Naked) noreturn {
232232 );
233233 }
234234
235 // Move this to the riscv prong below when this is resolved: https://github.com/ziglang/zig/issues/20918
236 if (builtin.cpu.arch.isRISCV() and builtin.zig_backend != .stage2_riscv64) asm volatile (
237 \\ .weak __global_pointer$
238 \\ .hidden __global_pointer$
239 \\ .option push
240 \\ .option norelax
241 \\ lla gp, __global_pointer$
242 \\ .option pop
243 );
244
235245 // Note that we maintain a very low level of trust with regards to ABI guarantees at this point.
236246 // We will redundantly align the stack, clear the link register, etc. While e.g. the Linux
237247 // kernel is usually good about upholding the ABI guarantees, the same cannot be said of dynamic
......@@ -275,24 +285,19 @@ fn _start() callconv(.Naked) noreturn {
275285 \\ and sp, #-16
276286 \\ b %[posixCallMainAndExit]
277287 ,
278 // zig fmt: off
279288 .csky =>
280 if (builtin.position_independent_code)
281 // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for
282 // position-independent code to work. We depend on this in `std.os.linux.start_pie`
283 // to locate `_DYNAMIC` as well.
284 \\ grs t0, 1f
285 \\ 1:
286 \\ lrw gb, 1b@GOTPC
287 \\ addu gb, t0
288 else ""
289 ++
289 // The CSKY ABI assumes that `gb` is set to the address of the GOT in order for
290 // position-independent code to work. We depend on this in `std.os.linux.start_pie`
291 // to locate `_DYNAMIC` as well.
292 \\ grs t0, 1f
293 \\ 1:
294 \\ lrw gb, 1b@GOTPC
295 \\ addu gb, t0
290296 \\ movi lr, 0
291297 \\ mov a0, sp
292298 \\ andi sp, sp, -8
293299 \\ jmpi %[posixCallMainAndExit]
294300 ,
295 // zig fmt: on
296301 .hexagon =>
297302 // r29 = SP, r30 = FP
298303 \\ r30 = #0
......@@ -308,27 +313,13 @@ fn _start() callconv(.Naked) noreturn {
308313 \\ bstrins.d $sp, $zero, 3, 0
309314 \\ b %[posixCallMainAndExit]
310315 ,
311 // zig fmt: off
312316 .riscv32, .riscv64 =>
313 // The self-hosted riscv64 backend is not able to assemble this yet.
314 if (builtin.zig_backend != .stage2_riscv64)
315 // The RISC-V ELF ABI assumes that `gp` is set to the value of `__global_pointer$` at
316 // startup in order for GP relaxation to work, even in static builds.
317 \\ .weak __global_pointer$
318 \\ .hidden __global_pointer$
319 \\ .option push
320 \\ .option norelax
321 \\ lla gp, __global_pointer$
322 \\ .option pop
323 else ""
324 ++
325317 \\ li s0, 0
326318 \\ li ra, 0
327319 \\ mv a0, sp
328320 \\ andi sp, sp, -16
329321 \\ tail %[posixCallMainAndExit]@plt
330322 ,
331 // zig fmt: on
332323 .m68k =>
333324 // Note that the - 8 is needed because pc in the jsr instruction points into the middle
334325 // of the jsr instruction. (The lea is 6 bytes, the jsr is 4 bytes.)
src/codegen/llvm.zig+20-19
......@@ -2909,7 +2909,17 @@ pub const Object = struct {
29092909 function_index.setAlignment(resolved.alignment.toLlvm(), &o.builder);
29102910
29112911 // Function attributes that are independent of analysis results of the function body.
2912 try o.addCommonFnAttributes(&attributes, owner_mod);
2912 try o.addCommonFnAttributes(
2913 &attributes,
2914 owner_mod,
2915 // Some backends don't respect the `naked` attribute in `TargetFrameLowering::hasFP()`,
2916 // so for these backends, LLVM will happily emit code that accesses the stack through
2917 // the frame pointer. This is nonsensical since what the `naked` attribute does is
2918 // suppress generation of the prologue and epilogue, and the prologue is where the
2919 // frame pointer normally gets set up. At time of writing, this is the case for at
2920 // least x86 and RISC-V.
2921 owner_mod.omit_frame_pointer or fn_info.cc == .Naked,
2922 );
29132923
29142924 if (fn_info.return_type == .noreturn_type) try attributes.addFnAttr(.noreturn, &o.builder);
29152925
......@@ -2956,13 +2966,14 @@ pub const Object = struct {
29562966 o: *Object,
29572967 attributes: *Builder.FunctionAttributes.Wip,
29582968 owner_mod: *Package.Module,
2969 omit_frame_pointer: bool,
29592970 ) Allocator.Error!void {
29602971 const comp = o.pt.zcu.comp;
29612972
29622973 if (!owner_mod.red_zone) {
29632974 try attributes.addFnAttr(.noredzone, &o.builder);
29642975 }
2965 if (owner_mod.omit_frame_pointer) {
2976 if (omit_frame_pointer) {
29662977 try attributes.addFnAttr(.{ .string = .{
29672978 .kind = try o.builder.string("frame-pointer"),
29682979 .value = try o.builder.string("none"),
......@@ -4528,7 +4539,7 @@ pub const Object = struct {
45284539
45294540 var attributes: Builder.FunctionAttributes.Wip = .{};
45304541 defer attributes.deinit(&o.builder);
4531 try o.addCommonFnAttributes(&attributes, zcu.root_mod);
4542 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
45324543
45334544 function_index.setLinkage(.internal, &o.builder);
45344545 function_index.setCallConv(.fastcc, &o.builder);
......@@ -4557,7 +4568,7 @@ pub const Object = struct {
45574568
45584569 var attributes: Builder.FunctionAttributes.Wip = .{};
45594570 defer attributes.deinit(&o.builder);
4560 try o.addCommonFnAttributes(&attributes, zcu.root_mod);
4571 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
45614572
45624573 function_index.setLinkage(.internal, &o.builder);
45634574 function_index.setCallConv(.fastcc, &o.builder);
......@@ -6709,8 +6720,6 @@ pub const FuncGen = struct {
67096720 const operand_ty = self.typeOf(pl_op.operand);
67106721 const name = self.air.nullTerminatedString(pl_op.payload);
67116722
6712 if (needDbgVarWorkaround(o)) return .none;
6713
67146723 const debug_local_var = try o.builder.debugLocalVar(
67156724 try o.builder.metadataString(name),
67166725 self.file,
......@@ -6734,7 +6743,10 @@ pub const FuncGen = struct {
67346743 },
67356744 "",
67366745 );
6737 } else if (owner_mod.optimize_mode == .Debug) {
6746 } else if (owner_mod.optimize_mode == .Debug and !self.is_naked) {
6747 // We avoid taking this path for naked functions because there's no guarantee that such
6748 // functions even have a valid stack pointer, making the `alloca` + `store` unsafe.
6749
67386750 const alignment = operand_ty.abiAlignment(pt).toLlvm();
67396751 const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
67406752 _ = try self.wip.store(.normal, operand, alloca, alignment);
......@@ -8815,7 +8827,6 @@ pub const FuncGen = struct {
88158827 if (self.is_naked) return arg_val;
88168828
88178829 const inst_ty = self.typeOfIndex(inst);
8818 if (needDbgVarWorkaround(o)) return arg_val;
88198830
88208831 const name = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.name;
88218832 if (name == .none) return arg_val;
......@@ -9676,7 +9687,7 @@ pub const FuncGen = struct {
96769687
96779688 var attributes: Builder.FunctionAttributes.Wip = .{};
96789689 defer attributes.deinit(&o.builder);
9679 try o.addCommonFnAttributes(&attributes, zcu.root_mod);
9690 try o.addCommonFnAttributes(&attributes, zcu.root_mod, zcu.root_mod.omit_frame_pointer);
96809691
96819692 function_index.setLinkage(.internal, &o.builder);
96829693 function_index.setCallConv(.fastcc, &o.builder);
......@@ -11820,16 +11831,6 @@ const optional_layout_version = 3;
1182011831
1182111832const lt_errors_fn_name = "__zig_lt_errors_len";
1182211833
11823/// Without this workaround, LLVM crashes with "unknown codeview register H1"
11824/// https://github.com/llvm/llvm-project/issues/56484
11825fn needDbgVarWorkaround(o: *Object) bool {
11826 const target = o.pt.zcu.getTarget();
11827 if (target.os.tag == .windows and target.cpu.arch == .aarch64) {
11828 return true;
11829 }
11830 return false;
11831}
11832
1183311834fn compilerRtIntBits(bits: u16) u16 {
1183411835 inline for (.{ 32, 64, 128 }) |b| {
1183511836 if (bits <= b) {