authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-21 18:46:53+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-21 20:43:10+01:00
log05330bbe0ddd3057a1badea92a7823a2b1f4d68a
tree5024eec9fd027492fdaef8270f2322f654d51969
parent110c18588688e4c03010e372668bbb0ab90e4735

stage2: ensure 16byte stack alignment on macOS x86_64


1 files changed, 48 insertions(+), 31 deletions(-)

src/arch/x86_64/CodeGen.zig+48-31
......@@ -382,12 +382,10 @@ fn gen(self: *Self) InnerError!void {
382382 // yet know how big it will be, so we leave room for a 4-byte stack size.
383383 // TODO During semantic analysis, check if there are no function calls. If there
384384 // are none, here we can omit the part where we subtract and then add rsp.
385 const backpatch_reloc = try self.addInst(.{
386 .tag = .sub,
387 .ops = (Mir.Ops{
388 .reg1 = .rsp,
389 }).encode(),
390 .data = .{ .imm = 0 },
385 const backpatch_stack_sub = try self.addInst(.{
386 .tag = .nop,
387 .ops = undefined,
388 .data = undefined,
391389 });
392390
393391 _ = try self.addInst(.{
......@@ -398,21 +396,6 @@ fn gen(self: *Self) InnerError!void {
398396
399397 try self.genBody(self.air.getMainBody());
400398
401 const stack_end = self.max_end_stack;
402 if (stack_end > math.maxInt(i32)) {
403 return self.failSymbol("too much stack used in call parameters", .{});
404 }
405 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
406 if (aligned_stack_end > 0) {
407 self.mir_instructions.items(.data)[backpatch_reloc].imm = @intCast(i32, aligned_stack_end);
408 } else {
409 self.mir_instructions.set(backpatch_reloc, .{
410 .tag = .nop,
411 .ops = undefined,
412 .data = undefined,
413 });
414 }
415
416399 if (self.exitlude_jump_relocs.items.len == 1) {
417400 self.mir_instructions.len -= 1;
418401 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
......@@ -425,16 +408,12 @@ fn gen(self: *Self) InnerError!void {
425408 .data = undefined,
426409 });
427410
428 if (aligned_stack_end > 0) {
429 // add rsp, x
430 _ = try self.addInst(.{
431 .tag = .add,
432 .ops = (Mir.Ops{
433 .reg1 = .rsp,
434 }).encode(),
435 .data = .{ .imm = @intCast(i32, aligned_stack_end) },
436 });
437 }
411 // Maybe add rsp, x if required. This is backpatched later.
412 const backpatch_stack_add = try self.addInst(.{
413 .tag = .nop,
414 .ops = undefined,
415 .data = undefined,
416 });
438417
439418 _ = try self.addInst(.{
440419 .tag = .pop,
......@@ -443,11 +422,26 @@ fn gen(self: *Self) InnerError!void {
443422 }).encode(),
444423 .data = undefined,
445424 });
425
446426 // calculate the data for callee_preserved_regs to be pushed and popped
447427 var callee_preserved_regs_push_data: u32 = 0x0;
428 // TODO this is required on macOS since macOS actively checks for stack alignment
429 // at every extern call site. As far as I can tell, macOS accounts for the typical
430 // function prologue first 2 instructions of:
431 // ...
432 // push rbp
433 // mov rsp, rbp
434 // ...
435 // Thus we don't need to adjust the stack for the first push instruction. However,
436 // any subsequent push of values on the stack such as when preserving registers,
437 // needs to be taken into account here.
438 var stack_adjustment: i32 = 0;
448439 inline for (callee_preserved_regs) |reg, i| {
449440 if (self.register_manager.isRegAllocated(reg)) {
450441 callee_preserved_regs_push_data |= 1 << @intCast(u5, i);
442 if (self.target.isDarwin()) {
443 stack_adjustment += @divExact(reg.size(), 8);
444 }
451445 }
452446 }
453447 const data = self.mir_instructions.items(.data);
......@@ -466,6 +460,29 @@ fn gen(self: *Self) InnerError!void {
466460 }).encode(),
467461 .data = undefined,
468462 });
463
464 // Adjust the stack
465 const stack_end = self.max_end_stack;
466 if (stack_end > math.maxInt(i32) - stack_adjustment) {
467 return self.failSymbol("too much stack used in call parameters", .{});
468 }
469 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
470 if (aligned_stack_end > 0 or stack_adjustment > 0) {
471 self.mir_instructions.set(backpatch_stack_sub, .{
472 .tag = .sub,
473 .ops = (Mir.Ops{
474 .reg1 = .rsp,
475 }).encode(),
476 .data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment },
477 });
478 self.mir_instructions.set(backpatch_stack_add, .{
479 .tag = .add,
480 .ops = (Mir.Ops{
481 .reg1 = .rsp,
482 }).encode(),
483 .data = .{ .imm = @intCast(i32, aligned_stack_end) + stack_adjustment },
484 });
485 }
469486 } else {
470487 _ = try self.addInst(.{
471488 .tag = .dbg_prologue_end,