authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-11 15:02:17+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-11 15:02:17+01:00
loge1a535360fb9ed08fc48018571b9702ab12a5876
tree298c559ac845e266a2c8b0337775021036e17be1
parentf0400ad93eac984332c938b39e9c1627062d6b6a
parentcad3e3e63a238902cdd80eb2504c879d6637a4d5
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10862 from ziglang/elf-lower-slices

stage2: native backends: lower const slices

17 files changed, 411 insertions(+), 162 deletions(-)

src/arch/aarch64/CodeGen.zig+15-1
......@@ -1617,7 +1617,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
16171617
16181618 _ = try self.addInst(.{
16191619 .tag = .call_extern,
1620 .data = .{ .extern_fn = n_strx },
1620 .data = .{
1621 .extern_fn = .{
1622 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
1623 .sym_name = n_strx,
1624 },
1625 },
16211626 });
16221627 } else {
16231628 return self.fail("TODO implement calling bitcasted functions", .{});
......@@ -2485,9 +2490,18 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
24852490 });
24862491 },
24872492 .memory => |addr| {
2493 const owner_decl = self.mod_fn.owner_decl;
2494 // TODO when refactoring LinkBlock, make this into a generic function.
2495 const atom_index = switch (self.bin_file.tag) {
2496 .macho => owner_decl.link.macho.local_sym_index,
2497 .elf => owner_decl.link.elf.local_sym_index,
2498 .plan9 => @intCast(u32, owner_decl.link.plan9.sym_index orelse 0),
2499 else => return self.fail("TODO handle aarch64 load memory in {}", .{self.bin_file.tag}),
2500 };
24882501 _ = try self.addInst(.{
24892502 .tag = .load_memory,
24902503 .data = .{ .payload = try self.addExtra(Mir.LoadMemory{
2504 .atom_index = atom_index,
24912505 .register = @enumToInt(reg),
24922506 .addr = @intCast(u32, addr),
24932507 }) },
src/arch/aarch64/Emit.zig+7-7
......@@ -537,7 +537,7 @@ fn mirDebugEpilogueBegin(self: *Emit) !void {
537537
538538fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
539539 assert(emit.mir.instructions.items(.tag)[inst] == .call_extern);
540 const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn;
540 const extern_fn = emit.mir.instructions.items(.data)[inst].extern_fn;
541541
542542 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
543543 const offset = blk: {
......@@ -547,9 +547,10 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
547547 break :blk offset;
548548 };
549549 // Add relocation to the decl.
550 try macho_file.active_decl.?.link.macho.relocs.append(emit.bin_file.allocator, .{
550 const atom = macho_file.atom_by_index_table.get(extern_fn.atom_index).?;
551 try atom.relocs.append(emit.bin_file.allocator, .{
551552 .offset = offset,
552 .target = .{ .global = n_strx },
553 .target = .{ .global = extern_fn.sym_name },
553554 .addend = 0,
554555 .subtractor = null,
555556 .pcrel = true,
......@@ -613,10 +614,9 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
613614 ));
614615
615616 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
616 // TODO I think the reloc might be in the wrong place.
617 const decl = macho_file.active_decl.?;
617 const atom = macho_file.atom_by_index_table.get(load_memory.atom_index).?;
618618 // Page reloc for adrp instruction.
619 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
619 try atom.relocs.append(emit.bin_file.allocator, .{
620620 .offset = offset,
621621 .target = .{ .local = addr },
622622 .addend = 0,
......@@ -626,7 +626,7 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void {
626626 .@"type" = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),
627627 });
628628 // Pageoff reloc for adrp instruction.
629 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
629 try atom.relocs.append(emit.bin_file.allocator, .{
630630 .offset = offset + 4,
631631 .target = .{ .local = addr },
632632 .addend = 0,
src/arch/aarch64/Mir.zig+7-1
......@@ -134,7 +134,12 @@ pub const Inst = struct {
134134 /// An extern function
135135 ///
136136 /// Used by e.g. call_extern
137 extern_fn: u32,
137 extern_fn: struct {
138 /// Index of the containing atom.
139 atom_index: u32,
140 /// Index into the linker's string table.
141 sym_name: u32,
142 },
138143 /// A 16-bit immediate value.
139144 ///
140145 /// Used by e.g. svc
......@@ -278,6 +283,7 @@ pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end
278283}
279284
280285pub const LoadMemory = struct {
286 atom_index: u32,
281287 register: u32,
282288 addr: u32,
283289};
src/arch/arm/CodeGen.zig+11-14
......@@ -3931,23 +3931,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
39313931 switch (typed_value.ty.zigTypeTag()) {
39323932 .Pointer => switch (typed_value.ty.ptrSize()) {
39333933 .Slice => {
3934 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
3935 const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
3936 const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
3937 const slice_len = typed_value.val.sliceLen();
3938 // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean
3939 // the Sema code needs to use anonymous Decls or alloca instructions to store data.
3940 const ptr_imm = ptr_mcv.memory;
3941 _ = slice_len;
3942 _ = ptr_imm;
3943 // We need more general support for const data being stored in memory to make this work.
3944 return self.fail("TODO codegen for const slices", .{});
3934 return self.lowerUnnamedConst(typed_value);
39453935 },
39463936 else => {
3947 if (typed_value.val.tag() == .int_u64) {
3948 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
3937 switch (typed_value.val.tag()) {
3938 .int_u64 => {
3939 return MCValue{ .immediate = @intCast(u32, typed_value.val.toUnsignedInt()) };
3940 },
3941 .slice => {
3942 return self.lowerUnnamedConst(typed_value);
3943 },
3944 else => {
3945 return self.fail("TODO codegen more kinds of const pointers", .{});
3946 },
39493947 }
3950 return self.fail("TODO codegen more kinds of const pointers", .{});
39513948 },
39523949 },
39533950 .Int => {
src/arch/x86_64/CodeGen.zig+118-19
......@@ -1897,7 +1897,12 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
18971897 .reg1 = addr_reg.to64(),
18981898 .flags = flags,
18991899 }).encode(),
1900 .data = .{ .linker_sym_index = sym_index },
1900 .data = .{
1901 .load_reloc = .{
1902 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
1903 .sym_index = sym_index,
1904 },
1905 },
19011906 });
19021907 break :blk addr_reg;
19031908 },
......@@ -2670,7 +2675,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
26702675 _ = try self.addInst(.{
26712676 .tag = .call_extern,
26722677 .ops = undefined,
2673 .data = .{ .extern_fn = n_strx },
2678 .data = .{
2679 .extern_fn = .{
2680 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
2681 .sym_name = n_strx,
2682 },
2683 },
26742684 });
26752685 } else {
26762686 return self.fail("TODO implement calling bitcasted functions", .{});
......@@ -3514,8 +3524,14 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
35143524 else => return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv}),
35153525 }
35163526 },
3527 .embedded_in_code => {
3528 if (abi_size <= 8) {
3529 const reg = try self.copyToTmpRegister(ty, mcv);
3530 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
3531 }
3532 return self.fail("TODO implement args on stack for {} with abi size > 8", .{mcv});
3533 },
35173534 .memory,
3518 .embedded_in_code,
35193535 .direct_load,
35203536 .got_load,
35213537 => {
......@@ -3523,7 +3539,63 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
35233539 const reg = try self.copyToTmpRegister(ty, mcv);
35243540 return self.genSetStackArg(ty, stack_offset, MCValue{ .register = reg });
35253541 }
3526 return self.fail("TODO implement memcpy for setting args on stack from {}", .{mcv});
3542
3543 self.register_manager.freezeRegs(&.{ .rax, .rcx });
3544 defer self.register_manager.unfreezeRegs(&.{ .rax, .rcx });
3545
3546 const addr_reg: Register = blk: {
3547 switch (mcv) {
3548 .got_load,
3549 .direct_load,
3550 => |sym_index| {
3551 const flags: u2 = switch (mcv) {
3552 .got_load => 0b00,
3553 .direct_load => 0b01,
3554 else => unreachable,
3555 };
3556 const addr_reg = try self.register_manager.allocReg(null);
3557 _ = try self.addInst(.{
3558 .tag = .lea_pie,
3559 .ops = (Mir.Ops{
3560 .reg1 = addr_reg.to64(),
3561 .flags = flags,
3562 }).encode(),
3563 .data = .{
3564 .load_reloc = .{
3565 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
3566 .sym_index = sym_index,
3567 },
3568 },
3569 });
3570 break :blk addr_reg;
3571 },
3572 .memory => |addr| {
3573 const addr_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
3574 break :blk addr_reg;
3575 },
3576 else => unreachable,
3577 }
3578 };
3579
3580 self.register_manager.freezeRegs(&.{addr_reg});
3581 defer self.register_manager.unfreezeRegs(&.{addr_reg});
3582
3583 const regs = try self.register_manager.allocRegs(2, .{ null, null });
3584 const count_reg = regs[0];
3585 const tmp_reg = regs[1];
3586
3587 try self.register_manager.getReg(.rax, null);
3588 try self.register_manager.getReg(.rcx, null);
3589
3590 // TODO allow for abi_size to be u64
3591 try self.genSetReg(Type.u32, count_reg, .{ .immediate = @intCast(u32, abi_size) });
3592 try self.genInlineMemcpy(
3593 -(stack_offset + @intCast(i32, abi_size)),
3594 .rsp,
3595 addr_reg.to64(),
3596 count_reg.to64(),
3597 tmp_reg.to8(),
3598 );
35273599 },
35283600 .register => |reg| {
35293601 _ = try self.addInst(.{
......@@ -3710,6 +3782,30 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerErro
37103782 const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
37113783 break :blk reg;
37123784 },
3785 .direct_load,
3786 .got_load,
3787 => |sym_index| {
3788 const flags: u2 = switch (mcv) {
3789 .got_load => 0b00,
3790 .direct_load => 0b01,
3791 else => unreachable,
3792 };
3793 const addr_reg = try self.register_manager.allocReg(null);
3794 _ = try self.addInst(.{
3795 .tag = .lea_pie,
3796 .ops = (Mir.Ops{
3797 .reg1 = addr_reg.to64(),
3798 .flags = flags,
3799 }).encode(),
3800 .data = .{
3801 .load_reloc = .{
3802 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
3803 .sym_index = sym_index,
3804 },
3805 },
3806 });
3807 break :blk addr_reg;
3808 },
37133809 else => {
37143810 return self.fail("TODO implement memcpy for setting stack from {}", .{mcv});
37153811 },
......@@ -4145,7 +4241,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
41454241 .reg1 = reg,
41464242 .flags = flags,
41474243 }).encode(),
4148 .data = .{ .linker_sym_index = sym_index },
4244 .data = .{
4245 .load_reloc = .{
4246 .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
4247 .sym_index = sym_index,
4248 },
4249 },
41494250 });
41504251 // MOV reg, [reg]
41514252 _ = try self.addInst(.{
......@@ -4488,6 +4589,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
44884589}
44894590
44904591fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
4592 log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty, tv.val });
44914593 const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| {
44924594 return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)});
44934595 };
......@@ -4520,23 +4622,20 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
45204622 switch (typed_value.ty.zigTypeTag()) {
45214623 .Pointer => switch (typed_value.ty.ptrSize()) {
45224624 .Slice => {
4523 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
4524 const ptr_type = typed_value.ty.slicePtrFieldType(&buf);
4525 const ptr_mcv = try self.genTypedValue(.{ .ty = ptr_type, .val = typed_value.val });
4526 const slice_len = typed_value.val.sliceLen();
4527 // Codegen can't handle some kinds of indirection. If the wrong union field is accessed here it may mean
4528 // the Sema code needs to use anonymous Decls or alloca instructions to store data.
4529 const ptr_imm = ptr_mcv.memory;
4530 _ = slice_len;
4531 _ = ptr_imm;
4532 // We need more general support for const data being stored in memory to make this work.
4533 return self.fail("TODO codegen for const slices", .{});
4625 return self.lowerUnnamedConst(typed_value);
45344626 },
45354627 else => {
4536 if (typed_value.val.tag() == .int_u64) {
4537 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
4628 switch (typed_value.val.tag()) {
4629 .int_u64 => {
4630 return MCValue{ .immediate = typed_value.val.toUnsignedInt() };
4631 },
4632 .slice => {
4633 return self.lowerUnnamedConst(typed_value);
4634 },
4635 else => {
4636 return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()});
4637 },
45384638 }
4539 return self.fail("TODO codegen more kinds of const pointers: {}", .{typed_value.val.tag()});
45404639 },
45414640 },
45424641 .Int => {
src/arch/x86_64/Emit.zig+12-7
......@@ -763,6 +763,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
763763 const tag = emit.mir.instructions.items(.tag)[inst];
764764 assert(tag == .lea_pie);
765765 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
766 const load_reloc = emit.mir.instructions.items(.data)[inst].load_reloc;
766767
767768 // lea reg1, [rip + reloc]
768769 // RM
......@@ -772,18 +773,19 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
772773 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
773774 emit.code,
774775 );
776
775777 const end_offset = emit.code.items.len;
776 const sym_index = emit.mir.instructions.items(.data)[inst].linker_sym_index;
778
777779 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
778780 const reloc_type = switch (ops.flags) {
779781 0b00 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
780782 0b01 => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
781783 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
782784 };
783 const decl = macho_file.active_decl.?;
784 try decl.link.macho.relocs.append(emit.bin_file.allocator, .{
785 const atom = macho_file.atom_by_index_table.get(load_reloc.atom_index).?;
786 try atom.relocs.append(emit.bin_file.allocator, .{
785787 .offset = @intCast(u32, end_offset - 4),
786 .target = .{ .local = sym_index },
788 .target = .{ .local = load_reloc.sym_index },
787789 .addend = 0,
788790 .subtractor = null,
789791 .pcrel = true,
......@@ -801,17 +803,20 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
801803fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
802804 const tag = emit.mir.instructions.items(.tag)[inst];
803805 assert(tag == .call_extern);
804 const n_strx = emit.mir.instructions.items(.data)[inst].extern_fn;
806 const extern_fn = emit.mir.instructions.items(.data)[inst].extern_fn;
807
805808 const offset = blk: {
806809 // callq
807810 try lowerToDEnc(.call_near, 0, emit.code);
808811 break :blk @intCast(u32, emit.code.items.len) - 4;
809812 };
813
810814 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
811815 // Add relocation to the decl.
812 try macho_file.active_decl.?.link.macho.relocs.append(emit.bin_file.allocator, .{
816 const atom = macho_file.atom_by_index_table.get(extern_fn.atom_index).?;
817 try atom.relocs.append(emit.bin_file.allocator, .{
813818 .offset = offset,
814 .target = .{ .global = n_strx },
819 .target = .{ .global = extern_fn.sym_name },
815820 .addend = 0,
816821 .subtractor = null,
817822 .pcrel = true,
src/arch/x86_64/Mir.zig+15-6
......@@ -185,7 +185,7 @@ pub const Inst = struct {
185185 /// 0b00 reg1, [rip + reloc] // via GOT emits X86_64_RELOC_GOT relocation
186186 /// 0b01 reg1, [rip + reloc] // direct load emits X86_64_RELOC_SIGNED relocation
187187 /// Notes:
188 /// * `Data` contains `linker_sym_index`
188 /// * `Data` contains `load_reloc`
189189 lea_pie,
190190
191191 /// ops flags: form:
......@@ -350,10 +350,19 @@ pub const Inst = struct {
350350 /// A 32-bit immediate value.
351351 imm: u32,
352352 /// An extern function.
353 /// Index into the linker's string table.
354 extern_fn: u32,
355 /// Entry in the linker's symbol table.
356 linker_sym_index: u32,
353 extern_fn: struct {
354 /// Index of the containing atom.
355 atom_index: u32,
356 /// Index into the linker's string table.
357 sym_name: u32,
358 },
359 /// PIE load relocation.
360 load_reloc: struct {
361 /// Index of the containing atom.
362 atom_index: u32,
363 /// Index into the linker's symbol table.
364 sym_index: u32,
365 },
357366 /// Index into `extra`. Meaning of what can be found there is context-dependent.
358367 payload: u32,
359368 };
......@@ -362,7 +371,7 @@ pub const Inst = struct {
362371 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
363372 comptime {
364373 if (builtin.mode != .Debug) {
365 assert(@sizeOf(Inst) == 8);
374 assert(@sizeOf(Data) == 8);
366375 }
367376 }
368377};
src/arch/x86_64/PrintMir.zig+2-2
......@@ -450,6 +450,7 @@ fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
450450
451451fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
452452 const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]);
453 const load_reloc = print.mir.instructions.items(.data)[inst].load_reloc;
453454 try w.print("lea {s}, ", .{@tagName(ops.reg1)});
454455 switch (ops.reg1.size()) {
455456 8 => try w.print("byte ptr ", .{}),
......@@ -459,9 +460,8 @@ fn mirLeaPie(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {
459460 else => unreachable,
460461 }
461462 try w.print("[rip + 0x0] ", .{});
462 const sym_index = print.mir.instructions.items(.data)[inst].linker_sym_index;
463463 if (print.bin_file.cast(link.File.MachO)) |macho_file| {
464 const target = macho_file.locals.items[sym_index];
464 const target = macho_file.locals.items[load_reloc.sym_index];
465465 const target_name = macho_file.getString(target.n_strx);
466466 try w.print("target@{s}", .{target_name});
467467 } else {
src/codegen.zig+12-19
......@@ -142,6 +142,7 @@ pub fn generateFunction(
142142
143143pub fn generateSymbol(
144144 bin_file: *link.File,
145 parent_atom_index: u32,
145146 src_loc: Module.SrcLoc,
146147 typed_value: TypedValue,
147148 code: *std.ArrayList(u8),
......@@ -177,7 +178,7 @@ pub fn generateSymbol(
177178 if (typed_value.ty.sentinel()) |sentinel| {
178179 try code.ensureUnusedCapacity(payload.data.len + 1);
179180 code.appendSliceAssumeCapacity(payload.data);
180 switch (try generateSymbol(bin_file, src_loc, .{
181 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
181182 .ty = typed_value.ty.elemType(),
182183 .val = sentinel,
183184 }, code, debug_output)) {
......@@ -197,7 +198,7 @@ pub fn generateSymbol(
197198 const elem_vals = typed_value.val.castTag(.array).?.data;
198199 const elem_ty = typed_value.ty.elemType();
199200 for (elem_vals) |elem_val| {
200 switch (try generateSymbol(bin_file, src_loc, .{
201 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
201202 .ty = elem_ty,
202203 .val = elem_val,
203204 }, code, debug_output)) {
......@@ -223,20 +224,19 @@ pub fn generateSymbol(
223224 .Pointer => switch (typed_value.val.tag()) {
224225 .variable => {
225226 const decl = typed_value.val.castTag(.variable).?.data.owner_decl;
226 return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output);
227 return lowerDeclRef(bin_file, parent_atom_index, src_loc, typed_value, decl, code, debug_output);
227228 },
228229 .decl_ref => {
229230 const decl = typed_value.val.castTag(.decl_ref).?.data;
230 return lowerDeclRef(bin_file, src_loc, typed_value, decl, code, debug_output);
231 return lowerDeclRef(bin_file, parent_atom_index, src_loc, typed_value, decl, code, debug_output);
231232 },
232233 .slice => {
233 // TODO populate .debug_info for the slice
234234 const slice = typed_value.val.castTag(.slice).?.data;
235235
236236 // generate ptr
237237 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
238238 const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
239 switch (try generateSymbol(bin_file, src_loc, .{
239 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
240240 .ty = slice_ptr_field_type,
241241 .val = slice.ptr,
242242 }, code, debug_output)) {
......@@ -248,7 +248,7 @@ pub fn generateSymbol(
248248 }
249249
250250 // generate length
251 switch (try generateSymbol(bin_file, src_loc, .{
251 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
252252 .ty = Type.initTag(.usize),
253253 .val = slice.len,
254254 }, code, debug_output)) {
......@@ -392,7 +392,7 @@ pub fn generateSymbol(
392392 const field_ty = typed_value.ty.structFieldType(index);
393393 if (!field_ty.hasRuntimeBits()) continue;
394394
395 switch (try generateSymbol(bin_file, src_loc, .{
395 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
396396 .ty = field_ty,
397397 .val = field_val,
398398 }, code, debug_output)) {
......@@ -447,6 +447,7 @@ pub fn generateSymbol(
447447
448448fn lowerDeclRef(
449449 bin_file: *link.File,
450 parent_atom_index: u32,
450451 src_loc: Module.SrcLoc,
451452 typed_value: TypedValue,
452453 decl: *Module.Decl,
......@@ -457,7 +458,7 @@ fn lowerDeclRef(
457458 // generate ptr
458459 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
459460 const slice_ptr_field_type = typed_value.ty.slicePtrFieldType(&buf);
460 switch (try generateSymbol(bin_file, src_loc, .{
461 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
461462 .ty = slice_ptr_field_type,
462463 .val = typed_value.val,
463464 }, code, debug_output)) {
......@@ -473,7 +474,7 @@ fn lowerDeclRef(
473474 .base = .{ .tag = .int_u64 },
474475 .data = typed_value.val.sliceLen(),
475476 };
476 switch (try generateSymbol(bin_file, src_loc, .{
477 switch (try generateSymbol(bin_file, parent_atom_index, src_loc, .{
477478 .ty = Type.initTag(.usize),
478479 .val = Value.initPayload(&slice_len.base),
479480 }, code, debug_output)) {
......@@ -496,15 +497,7 @@ fn lowerDeclRef(
496497 }
497498
498499 decl.markAlive();
499 const vaddr = vaddr: {
500 if (bin_file.cast(link.File.MachO)) |macho_file| {
501 break :vaddr try macho_file.getDeclVAddrWithReloc(decl, code.items.len);
502 }
503 // TODO handle the dependency of this symbol on the decl's vaddr.
504 // If the decl changes vaddr, then this symbol needs to get regenerated.
505 break :vaddr bin_file.getDeclVAddr(decl);
506 };
507
500 const vaddr = try bin_file.getDeclVAddr(decl, parent_atom_index, code.items.len);
508501 const endian = target.cpu.arch.endian();
509502 switch (ptr_width) {
510503 16 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(u16, vaddr), endian),
src/link.zig+9-5
......@@ -684,12 +684,16 @@ pub const File = struct {
684684 }
685685 }
686686
687 pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 {
687 /// Get allocated `Decl`'s address in virtual memory.
688 /// The linker is passed information about the containing atom, `parent_atom_index`, and offset within it's
689 /// memory buffer, `offset`, so that it can make a note of potential relocation sites, should the
690 /// `Decl`'s address was not yet resolved, or the containing atom gets moved in virtual memory.
691 pub fn getDeclVAddr(base: *File, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
688692 switch (base.tag) {
689 .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl),
690 .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl),
691 .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl),
692 .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl),
693 .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
694 .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
695 .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
696 .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl, parent_atom_index, offset),
693697 .c => unreachable,
694698 .wasm => unreachable,
695699 .spirv => unreachable,
src/link/Coff.zig+5-3
......@@ -726,7 +726,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
726726 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
727727 defer code_buffer.deinit();
728728
729 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
729 const res = try codegen.generateSymbol(&self.base, 0, decl.srcLoc(), .{
730730 .ty = decl.ty,
731731 .val = decl.val,
732732 }, &code_buffer, .none);
......@@ -751,7 +751,7 @@ fn finishUpdateDecl(self: *Coff, module: *Module, decl: *Module.Decl, code: []co
751751 const need_realloc = code.len > capacity or
752752 !mem.isAlignedGeneric(u32, decl.link.coff.text_offset, required_alignment);
753753 if (need_realloc) {
754 const curr_vaddr = self.getDeclVAddr(decl);
754 const curr_vaddr = self.text_section_virtual_address + decl.link.coff.text_offset;
755755 const vaddr = try self.growTextBlock(&decl.link.coff, code.len, required_alignment);
756756 log.debug("growing {s} from 0x{x} to 0x{x}\n", .{ decl.name, curr_vaddr, vaddr });
757757 if (vaddr != curr_vaddr) {
......@@ -1465,7 +1465,9 @@ fn findLib(self: *Coff, arena: Allocator, name: []const u8) !?[]const u8 {
14651465 return null;
14661466}
14671467
1468pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl) u64 {
1468pub fn getDeclVAddr(self: *Coff, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
1469 _ = parent_atom_index;
1470 _ = offset;
14691471 assert(self.llvm_object == null);
14701472 return self.text_section_virtual_address + decl.link.coff.text_offset;
14711473}
src/link/Elf.zig+94-19
......@@ -145,6 +145,7 @@ decls: std.AutoHashMapUnmanaged(*Module.Decl, ?u16) = .{},
145145/// at present owned by Module.Decl.
146146/// TODO consolidate this.
147147managed_atoms: std.ArrayListUnmanaged(*TextBlock) = .{},
148atom_by_index_table: std.AutoHashMapUnmanaged(u32, *TextBlock) = .{},
148149
149150/// Table of unnamed constants associated with a parent `Decl`.
150151/// We store them here so that we can free the constants whenever the `Decl`
......@@ -179,6 +180,18 @@ dbg_info_decl_free_list: std.AutoHashMapUnmanaged(*TextBlock, void) = .{},
179180dbg_info_decl_first: ?*TextBlock = null,
180181dbg_info_decl_last: ?*TextBlock = null,
181182
183/// A table of relocations indexed by the owning them `TextBlock`.
184/// Note that once we refactor `TextBlock`'s lifetime and ownership rules,
185/// this will be a table indexed by index into the list of Atoms.
186relocs: RelocTable = .{},
187
188const Reloc = struct {
189 target: u32,
190 offset: u64,
191 prev_vaddr: u64,
192};
193
194const RelocTable = std.AutoHashMapUnmanaged(*TextBlock, std.ArrayListUnmanaged(Reloc));
182195const UnnamedConstTable = std.AutoHashMapUnmanaged(*Module.Decl, std.ArrayListUnmanaged(*TextBlock));
183196
184197/// When allocating, the ideal_capacity is calculated by
......@@ -397,12 +410,36 @@ pub fn deinit(self: *Elf) void {
397410 }
398411 self.unnamed_const_atoms.deinit(self.base.allocator);
399412 }
413
414 {
415 var it = self.relocs.valueIterator();
416 while (it.next()) |relocs| {
417 relocs.deinit(self.base.allocator);
418 }
419 self.relocs.deinit(self.base.allocator);
420 }
421
422 self.atom_by_index_table.deinit(self.base.allocator);
400423}
401424
402pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl) u64 {
425pub fn getDeclVAddr(self: *Elf, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
403426 assert(self.llvm_object == null);
404427 assert(decl.link.elf.local_sym_index != 0);
405 return self.local_symbols.items[decl.link.elf.local_sym_index].st_value;
428
429 const target = decl.link.elf.local_sym_index;
430 const vaddr = self.local_symbols.items[target].st_value;
431 const atom = self.atom_by_index_table.get(parent_atom_index).?;
432 const gop = try self.relocs.getOrPut(self.base.allocator, atom);
433 if (!gop.found_existing) {
434 gop.value_ptr.* = .{};
435 }
436 try gop.value_ptr.append(self.base.allocator, .{
437 .target = target,
438 .offset = offset,
439 .prev_vaddr = vaddr,
440 });
441
442 return vaddr;
406443}
407444
408445fn getDebugLineProgramOff(self: Elf) u32 {
......@@ -991,6 +1028,41 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
9911028 .p64 => 12,
9921029 };
9931030
1031 {
1032 var it = self.relocs.iterator();
1033 while (it.next()) |entry| {
1034 const atom = entry.key_ptr.*;
1035 const relocs = entry.value_ptr.*;
1036 const source_sym = self.local_symbols.items[atom.local_sym_index];
1037 const source_shdr = self.sections.items[source_sym.st_shndx];
1038
1039 log.debug("relocating '{s}'", .{self.getString(source_sym.st_name)});
1040
1041 for (relocs.items) |*reloc| {
1042 const target_sym = self.local_symbols.items[reloc.target];
1043 const target_vaddr = target_sym.st_value;
1044
1045 if (target_vaddr == reloc.prev_vaddr) continue;
1046
1047 const section_offset = (source_sym.st_value + reloc.offset) - source_shdr.sh_addr;
1048 const file_offset = source_shdr.sh_offset + section_offset;
1049
1050 log.debug(" ({x}: [() => 0x{x}] ({s}))", .{
1051 reloc.offset,
1052 target_vaddr,
1053 self.getString(target_sym.st_name),
1054 });
1055
1056 switch (self.ptr_width) {
1057 .p32 => try self.base.file.?.pwriteAll(mem.asBytes(&@intCast(u32, target_vaddr)), file_offset),
1058 .p64 => try self.base.file.?.pwriteAll(mem.asBytes(&target_vaddr), file_offset),
1059 }
1060
1061 reloc.prev_vaddr = target_vaddr;
1062 }
1063 }
1064 }
1065
9941066 // Unfortunately these have to be buffered and done at the end because ELF does not allow
9951067 // mixing local and global symbols within a symbol table.
9961068 try self.writeAllGlobalSymbols();
......@@ -2508,6 +2580,7 @@ pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
25082580
25092581 log.debug("allocating symbol indexes for {s}", .{decl.name});
25102582 decl.link.elf.local_sym_index = try self.allocateLocalSymbol();
2583 try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.elf.local_sym_index, &decl.link.elf);
25112584
25122585 if (self.offset_table_free_list.popOrNull()) |i| {
25132586 decl.link.elf.offset_table_index = i;
......@@ -2525,6 +2598,7 @@ fn freeUnnamedConsts(self: *Elf, decl: *Module.Decl) void {
25252598 self.freeTextBlock(atom, self.phdr_load_ro_index.?);
25262599 self.local_symbol_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
25272600 self.local_symbols.items[atom.local_sym_index].st_info = 0;
2601 _ = self.atom_by_index_table.remove(atom.local_sym_index);
25282602 }
25292603 unnamed_consts.clearAndFree(self.base.allocator);
25302604}
......@@ -2543,11 +2617,11 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
25432617 // Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
25442618 if (decl.link.elf.local_sym_index != 0) {
25452619 self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
2546 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
2547
25482620 self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
2549
2621 _ = self.atom_by_index_table.remove(decl.link.elf.local_sym_index);
25502622 decl.link.elf.local_sym_index = 0;
2623
2624 self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
25512625 }
25522626 // TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
25532627 // is desired for both.
......@@ -2993,7 +3067,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
29933067
29943068 // TODO implement .debug_info for global variables
29953069 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
2996 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
3070 const res = try codegen.generateSymbol(&self.base, decl.link.elf.local_sym_index, decl.srcLoc(), .{
29973071 .ty = decl.ty,
29983072 .val = decl_val,
29993073 }, &code_buffer, .{
......@@ -3028,19 +3102,6 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl
30283102 }
30293103 const unnamed_consts = gop.value_ptr;
30303104
3031 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
3032 .none = .{},
3033 });
3034 const code = switch (res) {
3035 .externally_managed => |x| x,
3036 .appended => code_buffer.items,
3037 .fail => |em| {
3038 decl.analysis = .codegen_failure;
3039 try module.failed_decls.put(module.gpa, decl, em);
3040 return error.AnalysisFail;
3041 },
3042 };
3043
30443105 const atom = try self.base.allocator.create(TextBlock);
30453106 errdefer self.base.allocator.destroy(atom);
30463107 atom.* = TextBlock.empty;
......@@ -3056,6 +3117,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl: *Module.Decl
30563117
30573118 log.debug("allocating symbol indexes for {s}", .{name});
30583119 atom.local_sym_index = try self.allocateLocalSymbol();
3120 try self.atom_by_index_table.putNoClobber(self.base.allocator, atom.local_sym_index, atom);
3121
3122 const res = try codegen.generateSymbol(&self.base, atom.local_sym_index, decl.srcLoc(), typed_value, &code_buffer, .{
3123 .none = .{},
3124 });
3125 const code = switch (res) {
3126 .externally_managed => |x| x,
3127 .appended => code_buffer.items,
3128 .fail => |em| {
3129 decl.analysis = .codegen_failure;
3130 try module.failed_decls.put(module.gpa, decl, em);
3131 return error.AnalysisFail;
3132 },
3133 };
30593134
30603135 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
30613136 const phdr_index = self.phdr_load_ro_index.?;
src/link/MachO.zig+39-47
......@@ -40,6 +40,7 @@ const StringIndexContext = std.hash_map.StringIndexContext;
4040const Trie = @import("MachO/Trie.zig");
4141const Type = @import("../type.zig").Type;
4242const TypedValue = @import("../TypedValue.zig");
43const Value = @import("../value.zig").Value;
4344
4445pub const TextBlock = Atom;
4546
......@@ -220,6 +221,7 @@ atoms: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{},
220221/// at present owned by Module.Decl.
221222/// TODO consolidate this.
222223managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
224atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
223225
224226/// Table of unnamed constants associated with a parent `Decl`.
225227/// We store them here so that we can free the constants whenever the `Decl`
......@@ -248,12 +250,6 @@ unnamed_const_atoms: UnnamedConstTable = .{},
248250/// TODO consolidate this.
249251decls: std.AutoArrayHashMapUnmanaged(*Module.Decl, ?MatchingSection) = .{},
250252
251/// Currently active Module.Decl.
252/// TODO this might not be necessary if we figure out how to pass Module.Decl instance
253/// to codegen.genSetReg() or alternatively move PIE displacement for MCValue{ .memory = x }
254/// somewhere else in the codegen.
255active_decl: ?*Module.Decl = null,
256
257253const Entry = struct {
258254 target: Atom.Relocation.Target,
259255 atom: *Atom,
......@@ -3441,6 +3437,8 @@ pub fn deinit(self: *MachO) void {
34413437 }
34423438 self.unnamed_const_atoms.deinit(self.base.allocator);
34433439 }
3440
3441 self.atom_by_index_table.deinit(self.base.allocator);
34443442}
34453443
34463444pub fn closeFiles(self: MachO) void {
......@@ -3647,6 +3645,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
36473645 if (decl.link.macho.local_sym_index != 0) return;
36483646
36493647 decl.link.macho.local_sym_index = try self.allocateLocalSymbol();
3648 try self.atom_by_index_table.putNoClobber(self.base.allocator, decl.link.macho.local_sym_index, &decl.link.macho);
36503649 try self.decls.putNoClobber(self.base.allocator, decl, null);
36513650
36523651 const got_target = .{ .local = decl.link.macho.local_sym_index };
......@@ -3693,8 +3692,6 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
36933692 }
36943693 }
36953694
3696 self.active_decl = decl;
3697
36983695 const res = if (debug_buffers) |dbg|
36993696 try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{
37003697 .dwarf = .{
......@@ -3745,7 +3742,22 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
37453742 }
37463743 const unnamed_consts = gop.value_ptr;
37473744
3748 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
3745 const name_str_index = blk: {
3746 const index = unnamed_consts.items.len;
3747 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index });
3748 defer self.base.allocator.free(name);
3749 break :blk try self.makeString(name);
3750 };
3751 const name = self.getString(name_str_index);
3752
3753 log.debug("allocating symbol indexes for {s}", .{name});
3754
3755 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
3756 const local_sym_index = try self.allocateLocalSymbol();
3757 const atom = try self.createEmptyAtom(local_sym_index, @sizeOf(u64), math.log2(required_alignment));
3758 try self.atom_by_index_table.putNoClobber(self.base.allocator, local_sym_index, atom);
3759
3760 const res = try codegen.generateSymbol(&self.base, local_sym_index, decl.srcLoc(), typed_value, &code_buffer, .{
37493761 .none = .{},
37503762 });
37513763 const code = switch (res) {
......@@ -3758,26 +3770,10 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
37583770 },
37593771 };
37603772
3761 const name_str_index = blk: {
3762 const index = unnamed_consts.items.len;
3763 const name = try std.fmt.allocPrint(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, index });
3764 defer self.base.allocator.free(name);
3765 break :blk try self.makeString(name);
3766 };
3767 const name = self.getString(name_str_index);
3773 atom.code.clearRetainingCapacity();
3774 try atom.code.appendSlice(self.base.allocator, code);
37683775
3769 log.debug("allocating symbol indexes for {s}", .{name});
3770
3771 const required_alignment = typed_value.ty.abiAlignment(self.base.options.target);
3772 const match = (try self.getMatchingSection(.{
3773 .segname = makeStaticString("__TEXT"),
3774 .sectname = makeStaticString("__const"),
3775 .size = code.len,
3776 .@"align" = math.log2(required_alignment),
3777 })).?;
3778 const local_sym_index = try self.allocateLocalSymbol();
3779 const atom = try self.createEmptyAtom(local_sym_index, code.len, math.log2(required_alignment));
3780 mem.copy(u8, atom.code.items, code);
3776 const match = try self.getMatchingSectionAtom(atom, typed_value.ty, typed_value.val);
37813777 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);
37823778
37833779 log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });
......@@ -3837,11 +3833,9 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
38373833 }
38383834 }
38393835
3840 self.active_decl = decl;
3841
38423836 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
38433837 const res = if (debug_buffers) |dbg|
3844 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
3838 try codegen.generateSymbol(&self.base, decl.link.macho.local_sym_index, decl.srcLoc(), .{
38453839 .ty = decl.ty,
38463840 .val = decl_val,
38473841 }, &code_buffer, .{
......@@ -3852,7 +3846,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
38523846 },
38533847 })
38543848 else
3855 try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
3849 try codegen.generateSymbol(&self.base, decl.link.macho.local_sym_index, decl.srcLoc(), .{
38563850 .ty = decl.ty,
38573851 .val = decl_val,
38583852 }, &code_buffer, .none);
......@@ -3906,13 +3900,11 @@ fn isElemTyPointer(ty: Type) bool {
39063900 }
39073901}
39083902
3909fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection {
3910 const code = decl.link.macho.code.items;
3911 const alignment = decl.ty.abiAlignment(self.base.options.target);
3903fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !MatchingSection {
3904 const code = atom.code.items;
3905 const alignment = ty.abiAlignment(self.base.options.target);
39123906 const align_log_2 = math.log2(alignment);
3913 const ty = decl.ty;
39143907 const zig_ty = ty.zigTypeTag();
3915 const val = decl.val;
39163908 const mode = self.base.options.optimize_mode;
39173909 const match: MatchingSection = blk: {
39183910 // TODO finish and audit this function
......@@ -4021,9 +4013,11 @@ fn getMatchingSectionDecl(self: *MachO, decl: *Module.Decl) !MatchingSection {
40214013 },
40224014 }
40234015 };
4016 const local = self.locals.items[atom.local_sym_index];
40244017 const seg = self.load_commands.items[match.seg].segment;
40254018 const sect = seg.sections.items[match.sect];
4026 log.debug(" allocating atom in '{s},{s}' ({d},{d})", .{
4019 log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{
4020 self.getString(local.n_strx),
40274021 sect.segName(),
40284022 sect.sectName(),
40294023 match.seg,
......@@ -4039,7 +4033,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
40394033
40404034 const decl_ptr = self.decls.getPtr(decl).?;
40414035 if (decl_ptr.* == null) {
4042 decl_ptr.* = try self.getMatchingSectionDecl(decl);
4036 decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, decl.ty, decl.val);
40434037 }
40444038 const match = decl_ptr.*.?;
40454039
......@@ -4288,6 +4282,8 @@ fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {
42884282 }, true);
42894283 self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
42904284 self.locals.items[atom.local_sym_index].n_type = 0;
4285 _ = self.atom_by_index_table.remove(atom.local_sym_index);
4286 atom.local_sym_index = 0;
42914287 }
42924288 unnamed_consts.clearAndFree(self.base.allocator);
42934289}
......@@ -4314,6 +4310,7 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
43144310 }
43154311
43164312 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;
4313 _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index);
43174314 decl.link.macho.local_sym_index = 0;
43184315 }
43194316 if (self.d_sym) |*ds| {
......@@ -4341,16 +4338,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
43414338 }
43424339}
43434340
4344pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
4345 assert(decl.link.macho.local_sym_index != 0);
4346 return self.locals.items[decl.link.macho.local_sym_index].n_value;
4347}
4348
4349pub fn getDeclVAddrWithReloc(self: *MachO, decl: *const Module.Decl, offset: u64) !u64 {
4341pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
4342 assert(self.llvm_object == null);
43504343 assert(decl.link.macho.local_sym_index != 0);
4351 assert(self.active_decl != null);
43524344
4353 const atom = &self.active_decl.?.link.macho;
4345 const atom = self.atom_by_index_table.get(parent_atom_index).?;
43544346 try atom.relocs.append(self.base.allocator, .{
43554347 .offset = @intCast(u32, offset),
43564348 .target = .{ .local = decl.link.macho.local_sym_index },
src/link/Plan9.zig+6-2
......@@ -302,7 +302,9 @@ pub fn updateDecl(self: *Plan9, module: *Module, decl: *Module.Decl) !void {
302302 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
303303 defer code_buffer.deinit();
304304 const decl_val = if (decl.val.castTag(.variable)) |payload| payload.data.init else decl.val;
305 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), .{
305 // TODO we need the symbol index for symbol in the table of locals for the containing atom
306 const sym_index = decl.link.plan9.sym_index orelse 0;
307 const res = try codegen.generateSymbol(&self.base, @intCast(u32, sym_index), decl.srcLoc(), .{
306308 .ty = decl.ty,
307309 .val = decl_val,
308310 }, &code_buffer, .{ .none = .{} });
......@@ -749,7 +751,9 @@ pub fn allocateDeclIndexes(self: *Plan9, decl: *Module.Decl) !void {
749751 _ = self;
750752 _ = decl;
751753}
752pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl) u64 {
754pub fn getDeclVAddr(self: *Plan9, decl: *const Module.Decl, parent_atom_index: u32, offset: u64) !u64 {
755 _ = parent_atom_index;
756 _ = offset;
753757 if (decl.ty.zigTypeTag() == .Fn) {
754758 var start = self.bases.text;
755759 var it_file = self.fn_decl_table.iterator();
test/behavior.zig+1-1
......@@ -38,6 +38,7 @@ test {
3838 _ = @import("behavior/optional.zig");
3939 _ = @import("behavior/prefetch.zig");
4040 _ = @import("behavior/pub_enum.zig");
41 _ = @import("behavior/slice.zig");
4142 _ = @import("behavior/slice_sentinel_comptime.zig");
4243 _ = @import("behavior/type.zig");
4344 _ = @import("behavior/truncate.zig");
......@@ -76,7 +77,6 @@ test {
7677 _ = @import("behavior/pointers.zig");
7778 _ = @import("behavior/ptrcast.zig");
7879 _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig");
79 _ = @import("behavior/slice.zig");
8080 _ = @import("behavior/src.zig");
8181 _ = @import("behavior/this.zig");
8282 _ = @import("behavior/try.zig");
test/behavior/basic.zig-9
......@@ -120,14 +120,12 @@ test "return string from function" {
120120
121121test "hex escape" {
122122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
123 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
124123
125124 try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
126125}
127126
128127test "multiline string" {
129128 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
130 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
131129
132130 const s1 =
133131 \\one
......@@ -140,7 +138,6 @@ test "multiline string" {
140138
141139test "multiline string comments at start" {
142140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
143 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
144141
145142 const s1 =
146143 //\\one
......@@ -153,7 +150,6 @@ test "multiline string comments at start" {
153150
154151test "multiline string comments at end" {
155152 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
156 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
157153
158154 const s1 =
159155 \\one
......@@ -166,7 +162,6 @@ test "multiline string comments at end" {
166162
167163test "multiline string comments in middle" {
168164 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
169 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
170165
171166 const s1 =
172167 \\one
......@@ -179,7 +174,6 @@ test "multiline string comments in middle" {
179174
180175test "multiline string comments at multiple places" {
181176 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
182 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
183177
184178 const s1 =
185179 \\one
......@@ -193,14 +187,11 @@ test "multiline string comments at multiple places" {
193187}
194188
195189test "string concatenation" {
196 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
197
198190 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
199191}
200192
201193test "array mult operator" {
202194 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
204195
205196 try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
206197}
test/behavior/slice.zig+58
......@@ -27,7 +27,10 @@ comptime {
2727}
2828
2929test "slicing" {
30 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
3032 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
33
3134 var array: [20]i32 = undefined;
3235
3336 array[5] = 1234;
......@@ -45,6 +48,8 @@ test "slicing" {
4548
4649test "const slice" {
4750 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
51 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
52
4853 comptime {
4954 const a = "1234567890";
5055 try expect(a.len == 10);
......@@ -56,6 +61,8 @@ test "const slice" {
5661
5762test "comptime slice of undefined pointer of length 0" {
5863 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
64 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
65
5966 const slice1 = @as([*]i32, undefined)[0..0];
6067 try expect(slice1.len == 0);
6168 const slice2 = @as([*]i32, undefined)[100..100];
......@@ -64,6 +71,8 @@ test "comptime slice of undefined pointer of length 0" {
6471
6572test "implicitly cast array of size 0 to slice" {
6673 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
74 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
75
6776 var msg = [_]u8{};
6877 try assertLenIsZero(&msg);
6978}
......@@ -74,6 +83,8 @@ fn assertLenIsZero(msg: []const u8) !void {
7483
7584test "access len index of sentinel-terminated slice" {
7685 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
86 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87
7788 const S = struct {
7889 fn doTheTest() !void {
7990 var slice: [:0]const u8 = "hello";
......@@ -88,6 +99,8 @@ test "access len index of sentinel-terminated slice" {
8899
89100test "comptime slice of slice preserves comptime var" {
90101 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
103
91104 comptime {
92105 var buff: [10]u8 = undefined;
93106 buff[0..][0..][0] = 1;
......@@ -97,6 +110,8 @@ test "comptime slice of slice preserves comptime var" {
97110
98111test "slice of type" {
99112 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
114
100115 comptime {
101116 var types_array = [_]type{ i32, f64, type };
102117 for (types_array) |T, i| {
......@@ -120,6 +135,9 @@ test "slice of type" {
120135
121136test "generic malloc free" {
122137 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
139 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
140
123141 const a = memAlloc(u8, 10) catch unreachable;
124142 memFree(u8, a);
125143}
......@@ -133,6 +151,8 @@ fn memFree(comptime T: type, memory: []T) void {
133151
134152test "slice of hardcoded address to pointer" {
135153 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
155
136156 const S = struct {
137157 fn doTheTest() !void {
138158 const pointer = @intToPtr([*]u8, 0x04)[0..2];
......@@ -148,6 +168,8 @@ test "slice of hardcoded address to pointer" {
148168
149169test "comptime slice of pointer preserves comptime var" {
150170 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
172
151173 comptime {
152174 var buff: [10]u8 = undefined;
153175 var a = @ptrCast([*]u8, &buff);
......@@ -158,6 +180,8 @@ test "comptime slice of pointer preserves comptime var" {
158180
159181test "comptime pointer cast array and then slice" {
160182 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
183 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
184
161185 const array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8 };
162186
163187 const ptrA: [*]const u8 = @ptrCast([*]const u8, &array);
......@@ -172,6 +196,9 @@ test "comptime pointer cast array and then slice" {
172196
173197test "slicing zero length array" {
174198 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
199 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
200 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
201
175202 const s1 = ""[0..];
176203 const s2 = ([_]u32{})[0..];
177204 try expect(s1.len == 0);
......@@ -185,6 +212,8 @@ const y = x[0x100..];
185212test "compile time slice of pointer to hard coded address" {
186213 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
187214 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
215 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
216 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
188217
189218 try expect(@ptrToInt(x) == 0x1000);
190219 try expect(x.len == 0x500);
......@@ -194,6 +223,9 @@ test "compile time slice of pointer to hard coded address" {
194223}
195224
196225test "slice string literal has correct type" {
226 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
227 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
228
197229 comptime {
198230 try expect(@TypeOf("aoeu"[0..]) == *const [4:0]u8);
199231 const array = [_]i32{ 1, 2, 3, 4 };
......@@ -207,6 +239,7 @@ test "slice string literal has correct type" {
207239
208240test "result location zero sized array inside struct field implicit cast to slice" {
209241 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
242 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
210243
211244 const E = struct {
212245 entries: []u32,
......@@ -216,6 +249,9 @@ test "result location zero sized array inside struct field implicit cast to slic
216249}
217250
218251test "runtime safety lets us slice from len..len" {
252 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
253 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
254
219255 var an_array = [_]u8{ 1, 2, 3 };
220256 try expect(mem.eql(u8, sliceFromLenToLen(an_array[0..], 3, 3), ""));
221257}
......@@ -225,6 +261,9 @@ fn sliceFromLenToLen(a_slice: []u8, start: usize, end: usize) []u8 {
225261}
226262
227263test "C pointer" {
264 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
265 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
266
228267 var buf: [*c]const u8 = "kjdhfkjdhfdkjhfkfjhdfkjdhfkdjhfdkjhf";
229268 var len: u32 = 10;
230269 var slice = buf[0..len];
......@@ -232,6 +271,9 @@ test "C pointer" {
232271}
233272
234273test "C pointer slice access" {
274 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
275 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
276
235277 var buf: [10]u32 = [1]u32{42} ** 10;
236278 const c_ptr = @ptrCast([*c]const u32, &buf);
237279
......@@ -245,6 +287,8 @@ test "C pointer slice access" {
245287}
246288
247289test "comptime slices are disambiguated" {
290 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
291
248292 try expect(sliceSum(&[_]u8{ 1, 2 }) == 3);
249293 try expect(sliceSum(&[_]u8{ 3, 4 }) == 7);
250294}
......@@ -258,6 +302,9 @@ fn sliceSum(comptime q: []const u8) i32 {
258302}
259303
260304test "slice type with custom alignment" {
305 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
306 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
307
261308 const LazilyResolvedType = struct {
262309 anything: i32,
263310 };
......@@ -269,6 +316,8 @@ test "slice type with custom alignment" {
269316}
270317
271318test "obtaining a null terminated slice" {
319 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
320 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
272321 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
273322
274323 // here we have a normal array
......@@ -294,6 +343,7 @@ test "obtaining a null terminated slice" {
294343
295344test "empty array to slice" {
296345 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
297347
298348 const S = struct {
299349 fn doTheTest() !void {
......@@ -312,6 +362,9 @@ test "empty array to slice" {
312362}
313363
314364test "@ptrCast slice to pointer" {
365 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
366 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
367
315368 const S = struct {
316369 fn doTheTest() !void {
317370 var array align(@alignOf(u16)) = [5]u8{ 0xff, 0xff, 0xff, 0xff, 0xff };
......@@ -327,6 +380,7 @@ test "@ptrCast slice to pointer" {
327380
328381test "slice syntax resulting in pointer-to-array" {
329382 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
330384
331385 const S = struct {
332386 fn doTheTest() !void {
......@@ -475,6 +529,7 @@ test "slice syntax resulting in pointer-to-array" {
475529
476530test "type coercion of pointer to anon struct literal to pointer to slice" {
477531 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
478533
479534 const S = struct {
480535 const U = union {
......@@ -508,6 +563,7 @@ test "type coercion of pointer to anon struct literal to pointer to slice" {
508563
509564test "array concat of slices gives slice" {
510565 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
566 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
511567
512568 comptime {
513569 var a: []const u8 = "aoeu";
......@@ -519,6 +575,7 @@ test "array concat of slices gives slice" {
519575
520576test "slice bounds in comptime concatenation" {
521577 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
578 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
522579
523580 const bs = comptime blk: {
524581 const b = "........1........";
......@@ -535,6 +592,7 @@ test "slice bounds in comptime concatenation" {
535592
536593test "slice sentinel access at comptime" {
537594 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
538596
539597 {
540598 const str0 = &[_:0]u8{ '1', '2', '3' };