diff options
| author | Rue <78876133+IOKG04@users.noreply.github.com> | 2025-07-28 14:54:52 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-28 14:54:52 +0200 |
| commit | 5381e7891dcdd7b6a9e74250cdcce221fe464cdc (patch) | |
| tree | 4c74744ed84120dccae6dc9811ce945911108a17 /src/link | |
| parent | 84ae54fbe64a15301317716e7f901d81585332d5 (diff) | |
| parent | dea3ed7f59347e87a1b8fa237202873988084ae8 (diff) | |
| download | zig-5381e7891dcdd7b6a9e74250cdcce221fe464cdc.tar.gz zig-5381e7891dcdd7b6a9e74250cdcce221fe464cdc.zip | |
Merge branch 'ziglang:master' into some-documentation-updates-0
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Coff.zig | 76 | ||||
| -rw-r--r-- | src/link/Dwarf.zig | 8 | ||||
| -rw-r--r-- | src/link/Elf/Atom.zig | 70 | ||||
| -rw-r--r-- | src/link/Elf/Thunk.zig | 15 | ||||
| -rw-r--r-- | src/link/Elf/ZigObject.zig | 10 | ||||
| -rw-r--r-- | src/link/Elf/relocation.zig | 24 | ||||
| -rw-r--r-- | src/link/Elf/synthetic_sections.zig | 75 | ||||
| -rw-r--r-- | src/link/MachO.zig | 4 | ||||
| -rw-r--r-- | src/link/MachO/Atom.zig | 100 | ||||
| -rw-r--r-- | src/link/MachO/Thunk.zig | 10 | ||||
| -rw-r--r-- | src/link/MachO/ZigObject.zig | 10 | ||||
| -rw-r--r-- | src/link/MachO/synthetic.zig | 95 | ||||
| -rw-r--r-- | src/link/aarch64.zig | 64 |
13 files changed, 227 insertions, 334 deletions
diff --git a/src/link/Coff.zig b/src/link/Coff.zig index dd8ddd30f4..1b8986d337 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1335,9 +1335,13 @@ fn updateNavCode( log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); - const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; - const required_alignment = switch (pt.navAlignment(nav_index)) { - .none => target_util.defaultFunctionAlignment(target), + const mod = zcu.navFileScope(nav_index).mod.?; + const target = &mod.resolved_target.result; + const required_alignment = switch (nav.status.fully_resolved.alignment) { + .none => switch (mod.optimize_mode) { + .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), + .ReleaseSmall => target_util.minFunctionAlignment(target), + }, else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }; @@ -2832,58 +2836,33 @@ pub const Relocation = struct { }; fn resolveAarch64(reloc: Relocation, ctx: Context) void { + const Instruction = aarch64_util.encoding.Instruction; var buffer = ctx.code[reloc.offset..]; switch (reloc.type) { .got_page, .import_page, .page => { const source_page = @as(i32, @intCast(ctx.source_vaddr >> 12)); const target_page = @as(i32, @intCast(ctx.target_vaddr >> 12)); - const pages = @as(u21, @bitCast(@as(i21, @intCast(target_page - source_page)))); - var inst = aarch64_util.Instruction{ - .pc_relative_address = mem.bytesToValue(@FieldType( - aarch64_util.Instruction, - @tagName(aarch64_util.Instruction.pc_relative_address), - ), buffer[0..4]), - }; - inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); - inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); - mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); + const pages: i21 = @intCast(target_page - source_page); + var inst: Instruction = .read(buffer[0..Instruction.size]); + inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(pages >> 2); + inst.data_processing_immediate.pc_relative_addressing.group.immlo = @truncate(@as(u21, @bitCast(pages))); + inst.write(buffer[0..Instruction.size]); }, .got_pageoff, .import_pageoff, .pageoff => { assert(!reloc.pcrel); - const narrowed = @as(u12, @truncate(@as(u64, @intCast(ctx.target_vaddr)))); - if (isArithmeticOp(buffer[0..4])) { - var inst = aarch64_util.Instruction{ - .add_subtract_immediate = mem.bytesToValue(@FieldType( - aarch64_util.Instruction, - @tagName(aarch64_util.Instruction.add_subtract_immediate), - ), buffer[0..4]), - }; - inst.add_subtract_immediate.imm12 = narrowed; - mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); - } else { - var inst = aarch64_util.Instruction{ - .load_store_register = mem.bytesToValue(@FieldType( - aarch64_util.Instruction, - @tagName(aarch64_util.Instruction.load_store_register), - ), buffer[0..4]), - }; - const offset: u12 = blk: { - if (inst.load_store_register.size == 0) { - if (inst.load_store_register.v == 1) { - // 128-bit SIMD is scaled by 16. - break :blk @divExact(narrowed, 16); - } - // Otherwise, 8-bit SIMD or ldrb. - break :blk narrowed; - } else { - const denom: u4 = math.powi(u4, 2, inst.load_store_register.size) catch unreachable; - break :blk @divExact(narrowed, denom); - } - }; - inst.load_store_register.offset = offset; - mem.writeInt(u32, buffer[0..4], inst.toU32(), .little); + const narrowed: u12 = @truncate(@as(u64, @intCast(ctx.target_vaddr))); + var inst: Instruction = .read(buffer[0..Instruction.size]); + switch (inst.decode()) { + else => unreachable, + .data_processing_immediate => inst.data_processing_immediate.add_subtract_immediate.group.imm12 = narrowed, + .load_store => |load_store| inst.load_store.register_unsigned_immediate.group.imm12 = + switch (load_store.register_unsigned_immediate.decode()) { + .integer => |integer| @shrExact(narrowed, @intFromEnum(integer.group.size)), + .vector => |vector| @shrExact(narrowed, @intFromEnum(vector.group.opc1.decode(vector.group.size))), + }, } + inst.write(buffer[0..Instruction.size]); }, .direct => { assert(!reloc.pcrel); @@ -2934,11 +2913,6 @@ pub const Relocation = struct { }, } } - - fn isArithmeticOp(inst: *const [4]u8) bool { - const group_decode = @as(u5, @truncate(inst[3])); - return ((group_decode >> 2) == 4); - } }; pub fn addRelocation(coff: *Coff, atom_index: Atom.Index, reloc: Relocation) !void { @@ -3112,7 +3086,7 @@ const Path = std.Build.Cache.Path; const Directory = std.Build.Cache.Directory; const Cache = std.Build.Cache; -const aarch64_util = @import("../arch/aarch64/bits.zig"); +const aarch64_util = link.aarch64; const allocPrint = std.fmt.allocPrint; const codegen = @import("../codegen.zig"); const link = @import("../link.zig"); diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index a1a9dedd4b..4262c329fa 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -2487,7 +2487,13 @@ fn initWipNavInner( try wip_nav.strp(nav.fqn.toSlice(ip)); const ty: Type = nav_val.typeOf(zcu); const addr: Loc = .{ .addr_reloc = sym_index }; - const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr; + const loc: Loc = if (decl.is_threadlocal) loc: { + const target = zcu.comp.root_mod.resolved_target.result; + break :loc switch (target.cpu.arch) { + .x86_64 => .{ .form_tls_address = &addr }, + else => .empty, + }; + } else addr; switch (decl.kind) { .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable, .@"const" => { diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 5966bae02c..4bb88f2af3 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1627,7 +1627,7 @@ const aarch64 = struct { const S_ = th.targetAddress(target_index, elf_file); break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; - aarch64_util.writeBranchImm(disp, code); + util.writeBranchImm(disp, code); }, .PREL32 => { @@ -1640,15 +1640,18 @@ const aarch64 = struct { mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little); }, + .ADR_PREL_LO21 => { + const value = math.cast(i21, S + A - P) orelse return error.Overflow; + util.writeAdrInst(value, code); + }, + .ADR_PREL_PG_HI21 => { // TODO: check for relaxation of ADRP+ADD - const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, S + A))); - aarch64_util.writeAdrpInst(pages, code); + util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code); }, .ADR_GOT_PAGE => if (target.flags.has_got) { - const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(P, G + GOT + A))); - aarch64_util.writeAdrpInst(pages, code); + util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code); } else { // TODO: relax var err = try diags.addErrorWithNotes(1); @@ -1663,12 +1666,12 @@ const aarch64 = struct { .LD64_GOT_LO12_NC => { assert(target.flags.has_got); const taddr = @as(u64, @intCast(G + GOT + A)); - aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); + util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); }, .ADD_ABS_LO12_NC => { const taddr = @as(u64, @intCast(S + A)); - aarch64_util.writeAddImmInst(@truncate(taddr), code); + util.writeAddImmInst(@truncate(taddr), code); }, .LDST8_ABS_LO12_NC, @@ -1687,57 +1690,54 @@ const aarch64 = struct { .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), else => unreachable, }; - aarch64_util.writeLoadStoreRegInst(off, code); + util.writeLoadStoreRegInst(off, code); }, .TLSLE_ADD_TPREL_HI12 => { const value = math.cast(i12, (S + A - TP) >> 12) orelse return error.Overflow; - aarch64_util.writeAddImmInst(@bitCast(value), code); + util.writeAddImmInst(@bitCast(value), code); }, .TLSLE_ADD_TPREL_LO12_NC => { const value: i12 = @truncate(S + A - TP); - aarch64_util.writeAddImmInst(@bitCast(value), code); + util.writeAddImmInst(@bitCast(value), code); }, .TLSIE_ADR_GOTTPREL_PAGE21 => { const S_ = target.gotTpAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); - aarch64_util.writeAdrpInst(pages, code); + util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); }, .TLSIE_LD64_GOTTPREL_LO12_NC => { const S_ = target.gotTpAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); - aarch64_util.writeLoadStoreRegInst(off, code); + util.writeLoadStoreRegInst(off, code); }, .TLSGD_ADR_PAGE21 => { const S_ = target.tlsGdAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); - aarch64_util.writeAdrpInst(pages, code); + util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); }, .TLSGD_ADD_LO12_NC => { const S_ = target.tlsGdAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); - aarch64_util.writeAddImmInst(off, code); + util.writeAddImmInst(off, code); }, .TLSDESC_ADR_PAGE21 => { if (target.flags.has_tlsdesc) { const S_ = target.tlsDescAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); - const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(P, S_ + A)); - aarch64_util.writeAdrpInst(pages, code); + util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); } else { relocs_log.debug(" relaxing adrp => nop", .{}); - mem.writeInt(u32, code, Instruction.nop().toU32(), .little); + util.encoding.Instruction.nop().write(code); } }, @@ -1746,10 +1746,10 @@ const aarch64 = struct { const S_ = target.tlsDescAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); - aarch64_util.writeLoadStoreRegInst(off, code); + util.writeLoadStoreRegInst(off, code); } else { relocs_log.debug(" relaxing ldr => nop", .{}); - mem.writeInt(u32, code, Instruction.nop().toU32(), .little); + util.encoding.Instruction.nop().write(code); } }, @@ -1758,32 +1758,18 @@ const aarch64 = struct { const S_ = target.tlsDescAddress(elf_file); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); - aarch64_util.writeAddImmInst(off, code); + util.writeAddImmInst(off, code); } else { - const old_inst: Instruction = .{ - .add_subtract_immediate = mem.bytesToValue(@FieldType( - Instruction, - @tagName(Instruction.add_subtract_immediate), - ), code), - }; - const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd); - relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP }); + relocs_log.debug(" relaxing add => movz(x0, {x})", .{S + A - TP}); const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow); - mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little); + util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code); } }, .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { - const old_inst: Instruction = .{ - .unconditional_branch_register = mem.bytesToValue(@FieldType( - Instruction, - @tagName(Instruction.unconditional_branch_register), - ), code), - }; - const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn); - relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP }); + relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP}); const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); - mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little); + util.encoding.Instruction.movk(.x0, value, .{}).write(code); }, else => try atom.reportUnhandledRelocError(rel, elf_file), @@ -1819,9 +1805,7 @@ const aarch64 = struct { } } - const aarch64_util = @import("../aarch64.zig"); - const Instruction = aarch64_util.Instruction; - const Register = aarch64_util.Register; + const util = @import("../aarch64.zig"); }; const riscv = struct { diff --git a/src/link/Elf/Thunk.zig b/src/link/Elf/Thunk.zig index 2af0c9c9d3..59b867be78 100644 --- a/src/link/Elf/Thunk.zig +++ b/src/link/Elf/Thunk.zig @@ -95,18 +95,21 @@ const aarch64 = struct { const sym = elf_file.symbol(ref).?; const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size)); const taddr = sym.address(.{}, elf_file); - const pages = try util.calcNumberOfPages(saddr, taddr); - try writer.writeInt(u32, Instruction.adrp(.x16, pages).toU32(), .little); - const off: u12 = @truncate(@as(u64, @bitCast(taddr))); - try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); - try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); + try writer.writeInt(u32, @bitCast( + util.encoding.Instruction.adrp(.x16, try util.calcNumberOfPages(saddr, taddr) << 12), + ), .little); + try writer.writeInt(u32, @bitCast(util.encoding.Instruction.add( + .x16, + .x16, + .{ .immediate = @truncate(@as(u64, @bitCast(taddr))) }, + )), .little); + try writer.writeInt(u32, @bitCast(util.encoding.Instruction.br(.x16)), .little); } } const trampoline_size = 3 * @sizeOf(u32); const util = @import("../aarch64.zig"); - const Instruction = util.Instruction; }; const assert = std.debug.assert; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index c8f37125ed..f49406b751 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1270,9 +1270,13 @@ fn updateNavCode( log.debug("updateNavCode {f}({d})", .{ nav.fqn.fmt(ip), nav_index }); - const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; - const required_alignment = switch (pt.navAlignment(nav_index)) { - .none => target_util.defaultFunctionAlignment(target), + const mod = zcu.navFileScope(nav_index).mod.?; + const target = &mod.resolved_target.result; + const required_alignment = switch (nav.status.fully_resolved.alignment) { + .none => switch (mod.optimize_mode) { + .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), + .ReleaseSmall => target_util.minFunctionAlignment(target), + }, else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }; diff --git a/src/link/Elf/relocation.zig b/src/link/Elf/relocation.zig index 305dcda789..366d19d9b3 100644 --- a/src/link/Elf/relocation.zig +++ b/src/link/Elf/relocation.zig @@ -94,14 +94,18 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 { pub const dwarf = struct { pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 { return switch (cpu_arch) { - .x86_64 => @intFromEnum(switch (format) { - .@"32" => elf.R_X86_64.@"32", + .x86_64 => @intFromEnum(@as(elf.R_X86_64, switch (format) { + .@"32" => .@"32", .@"64" => .@"64", - }), - .riscv64 => @intFromEnum(switch (format) { - .@"32" => elf.R_RISCV.@"32", + })), + .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (format) { + .@"32" => .ABS32, + .@"64" => .ABS64, + })), + .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (format) { + .@"32" => .@"32", .@"64" => .@"64", - }), + })), else => @panic("TODO unhandled cpu arch"), }; } @@ -121,6 +125,14 @@ pub const dwarf = struct { }, .debug_frame => .PC32, })), + .aarch64 => @intFromEnum(@as(elf.R_AARCH64, switch (source_section) { + else => switch (address_size) { + .@"32" => .ABS32, + .@"64" => .ABS64, + else => unreachable, + }, + .debug_frame => .PREL32, + })), .riscv64 => @intFromEnum(@as(elf.R_RISCV, switch (source_section) { else => switch (address_size) { .@"32" => .@"32", diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 3f2ac7cb16..2ab71d8c49 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -810,54 +810,43 @@ pub const PltSection = struct { const got_plt_addr: i64 = @intCast(shdrs[elf_file.section_indexes.got_plt.?].sh_addr); // TODO: relax if possible // .got.plt[2] - const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); - const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(got_plt_addr + 16))), 8); + const pages = try util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); + const ldr_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); const add_off: u12 = @truncate(@as(u64, @bitCast(got_plt_addr + 16))); - const preamble = &[_]Instruction{ - Instruction.stp( - .x16, - .x30, - Register.sp, - Instruction.LoadStorePairOffset.pre_index(-16), - ), - Instruction.adrp(.x16, pages), - Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), - Instruction.add(.x16, .x16, add_off, false), - Instruction.br(.x17), - Instruction.nop(), - Instruction.nop(), - Instruction.nop(), + const preamble = [_]util.encoding.Instruction{ + .stp(.x16, .x30, .{ .pre_index = .{ .base = .sp, .index = -16 } }), + .adrp(.x16, pages << 12), + .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }), + .add(.x16, .x16, .{ .immediate = add_off }), + .br(.x17), + .nop(), + .nop(), + .nop(), }; comptime assert(preamble.len == 8); - for (preamble) |inst| { - try writer.writeInt(u32, inst.toU32(), .little); - } + for (preamble) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); } for (plt.symbols.items) |ref| { const sym = elf_file.symbol(ref).?; const target_addr = sym.gotPltAddress(elf_file); const source_addr = sym.pltAddress(elf_file); - const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); - const ldr_off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); + const pages = try util.calcNumberOfPages(source_addr, target_addr); + const ldr_off: u12 = @truncate(@as(u64, @bitCast(target_addr))); const add_off: u12 = @truncate(@as(u64, @bitCast(target_addr))); - const insts = &[_]Instruction{ - Instruction.adrp(.x16, pages), - Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), - Instruction.add(.x16, .x16, add_off, false), - Instruction.br(.x17), + const insts = [_]util.encoding.Instruction{ + .adrp(.x16, pages << 12), + .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = ldr_off } }), + .add(.x16, .x16, .{ .immediate = add_off }), + .br(.x17), }; comptime assert(insts.len == 4); - for (insts) |inst| { - try writer.writeInt(u32, inst.toU32(), .little); - } + for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); } } - const aarch64_util = @import("../aarch64.zig"); - const Instruction = aarch64_util.Instruction; - const Register = aarch64_util.Register; + const util = @import("../aarch64.zig"); }; }; @@ -979,24 +968,20 @@ pub const PltGotSection = struct { const sym = elf_file.symbol(ref).?; const target_addr = sym.gotAddress(elf_file); const source_addr = sym.pltGotAddress(elf_file); - const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr); - const off = try math.divExact(u12, @truncate(@as(u64, @bitCast(target_addr))), 8); - const insts = &[_]Instruction{ - Instruction.adrp(.x16, pages), - Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), - Instruction.br(.x17), - Instruction.nop(), + const pages = try util.calcNumberOfPages(source_addr, target_addr); + const off: u12 = @truncate(@as(u64, @bitCast(target_addr))); + const insts = [_]util.encoding.Instruction{ + .adrp(.x16, pages << 12), + .ldr(.x17, .{ .unsigned_offset = .{ .base = .x16, .offset = off } }), + .br(.x17), + .nop(), }; comptime assert(insts.len == 4); - for (insts) |inst| { - try writer.writeInt(u32, inst.toU32(), .little); - } + for (insts) |inst| try writer.writeInt(util.encoding.Instruction.Backing, @bitCast(inst), .little); } } - const aarch64_util = @import("../aarch64.zig"); - const Instruction = aarch64_util.Instruction; - const Register = aarch64_util.Register; + const util = @import("../aarch64.zig"); }; }; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 734b4b6a04..a3845727aa 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -328,6 +328,7 @@ pub fn deinit(self: *MachO) void { self.unwind_info.deinit(gpa); self.data_in_code.deinit(gpa); + for (self.thunks.items) |*thunk| thunk.deinit(gpa); self.thunks.deinit(gpa); } @@ -612,7 +613,6 @@ pub fn flush( }; const emit = self.base.emit; invalidateKernelCache(emit.root_dir.handle, emit.sub_path) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to invalidate kernel cache: {s}", .{@errorName(e)}), }; } @@ -5374,7 +5374,7 @@ const mem = std.mem; const meta = std.meta; const Writer = std.io.Writer; -const aarch64 = @import("../arch/aarch64/bits.zig"); +const aarch64 = codegen.aarch64.encoding; const bind = @import("MachO/dyld_info/bind.zig"); const calcUuid = @import("MachO/uuid.zig").calcUuid; const codegen = @import("../codegen.zig"); diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index e084ae0385..2ecd8da532 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -780,8 +780,7 @@ fn resolveRelocInner( }; break :target math.cast(u64, target) orelse return error.Overflow; }; - const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)))); - aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]); + aarch64.writeAdrInst(try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)), code[rel_offset..][0..aarch64.encoding.Instruction.size]); }, .pageoff => { @@ -789,26 +788,18 @@ fn resolveRelocInner( assert(rel.meta.length == 2); assert(!rel.meta.pcrel); const target = math.cast(u64, S + A) orelse return error.Overflow; - const inst_code = code[rel_offset..][0..4]; - if (aarch64.isArithmeticOp(inst_code)) { - aarch64.writeAddImmInst(@truncate(target), inst_code); - } else { - var inst = aarch64.Instruction{ - .load_store_register = mem.bytesToValue(@FieldType( - aarch64.Instruction, - @tagName(aarch64.Instruction.load_store_register), - ), inst_code), - }; - inst.load_store_register.offset = switch (inst.load_store_register.size) { - 0 => if (inst.load_store_register.v == 1) - try divExact(self, rel, @truncate(target), 16, macho_file) - else - @truncate(target), - 1 => try divExact(self, rel, @truncate(target), 2, macho_file), - 2 => try divExact(self, rel, @truncate(target), 4, macho_file), - 3 => try divExact(self, rel, @truncate(target), 8, macho_file), - }; - try writer.writeInt(u32, inst.toU32(), .little); + const inst_code = code[rel_offset..][0..aarch64.encoding.Instruction.size]; + var inst: aarch64.encoding.Instruction = .read(inst_code); + switch (inst.decode()) { + else => unreachable, + .data_processing_immediate => aarch64.writeAddImmInst(@truncate(target), inst_code), + .load_store => |load_store| { + inst.load_store.register_unsigned_immediate.group.imm12 = switch (load_store.register_unsigned_immediate.decode()) { + .integer => |integer| try divExact(self, rel, @truncate(target), @as(u4, 1) << @intFromEnum(integer.group.size), macho_file), + .vector => |vector| try divExact(self, rel, @truncate(target), @as(u5, 1) << @intFromEnum(vector.group.opc1.decode(vector.group.size)), macho_file), + }; + try writer.writeInt(u32, @bitCast(inst), .little); + }, } }, @@ -834,59 +825,26 @@ fn resolveRelocInner( break :target math.cast(u64, target) orelse return error.Overflow; }; - const RegInfo = struct { - rd: u5, - rn: u5, - size: u2, - }; - const inst_code = code[rel_offset..][0..4]; - const reg_info: RegInfo = blk: { - if (aarch64.isArithmeticOp(inst_code)) { - const inst = mem.bytesToValue(@FieldType( - aarch64.Instruction, - @tagName(aarch64.Instruction.add_subtract_immediate), - ), inst_code); - break :blk .{ - .rd = inst.rd, - .rn = inst.rn, - .size = inst.sf, - }; - } else { - const inst = mem.bytesToValue(@FieldType( - aarch64.Instruction, - @tagName(aarch64.Instruction.load_store_register), - ), inst_code); - break :blk .{ - .rd = inst.rt, - .rn = inst.rn, - .size = inst.size, - }; - } - }; - - var inst = if (sym.getSectionFlags().tlv_ptr) aarch64.Instruction{ - .load_store_register = .{ - .rt = reg_info.rd, - .rn = reg_info.rn, - .offset = try divExact(self, rel, @truncate(target), 8, macho_file), - .opc = 0b01, - .op1 = 0b01, - .v = 0, - .size = reg_info.size, + const rd, const rn = switch (aarch64.encoding.Instruction.read(inst_code).decode()) { + else => unreachable, + .data_processing_immediate => |decoded| .{ + decoded.add_subtract_immediate.group.Rd.decodeInteger(.doubleword, .{ .sp = true }), + decoded.add_subtract_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }), }, - } else aarch64.Instruction{ - .add_subtract_immediate = .{ - .rd = reg_info.rd, - .rn = reg_info.rn, - .imm12 = @truncate(target), - .sh = 0, - .s = 0, - .op = 0, - .sf = @as(u1, @truncate(reg_info.size)), + .load_store => |decoded| .{ + decoded.register_unsigned_immediate.integer.group.Rt.decodeInteger(.doubleword, .{}), + decoded.register_unsigned_immediate.group.Rn.decodeInteger(.doubleword, .{ .sp = true }), }, }; - try writer.writeInt(u32, inst.toU32(), .little); + + try writer.writeInt(u32, @bitCast(@as( + aarch64.encoding.Instruction, + if (sym.getSectionFlags().tlv_ptr) .ldr(rd, .{ .unsigned_offset = .{ + .base = rn, + .offset = try divExact(self, rel, @truncate(target), 8, macho_file) * 8, + } }) else .add(rd, rn, .{ .immediate = @truncate(target) }), + )), .little); }, } } diff --git a/src/link/MachO/Thunk.zig b/src/link/MachO/Thunk.zig index e9f67dd5e5..26432da1f5 100644 --- a/src/link/MachO/Thunk.zig +++ b/src/link/MachO/Thunk.zig @@ -21,15 +21,17 @@ pub fn getTargetAddress(thunk: Thunk, ref: MachO.Ref, macho_file: *MachO) u64 { } pub fn write(thunk: Thunk, macho_file: *MachO, writer: anytype) !void { + const Instruction = aarch64.encoding.Instruction; for (thunk.symbols.keys(), 0..) |ref, i| { const sym = ref.getSymbol(macho_file).?; const saddr = thunk.getAddress(macho_file) + i * trampoline_size; const taddr = sym.getAddress(.{}, macho_file); const pages = try aarch64.calcNumberOfPages(@intCast(saddr), @intCast(taddr)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off: u12 = @truncate(taddr); - try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); + try writer.writeInt(u32, @bitCast( + Instruction.add(.x16, .x16, .{ .immediate = @truncate(taddr) }), + ), .little); + try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little); } } diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index d6a56f8411..ef82f82e72 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -945,9 +945,13 @@ fn updateNavCode( log.debug("updateNavCode {f} 0x{x}", .{ nav.fqn.fmt(ip), nav_index }); - const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; - const required_alignment = switch (pt.navAlignment(nav_index)) { - .none => target_util.defaultFunctionAlignment(target), + const mod = zcu.navFileScope(nav_index).mod.?; + const target = &mod.resolved_target.result; + const required_alignment = switch (nav.status.fully_resolved.alignment) { + .none => switch (mod.optimize_mode) { + .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target), + .ReleaseSmall => target_util.minFunctionAlignment(target), + }, else => |a| a.maxStrict(target_util.minFunctionAlignment(target)), }; diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index c91c41df5f..22c44d2f7a 100644 --- a/src/link/MachO/synthetic.zig +++ b/src/link/MachO/synthetic.zig @@ -105,16 +105,15 @@ pub const StubsSection = struct { try writer.writeInt(i32, @intCast(target - source - 2 - 4), .little); }, .aarch64 => { + const Instruction = aarch64.encoding.Instruction; // TODO relax if possible const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try math.divExact(u12, @truncate(target), 8); - try writer.writeInt( - u32, - aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), - .little, - ); - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); + try writer.writeInt(u32, @bitCast(Instruction.ldr( + .x16, + .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } }, + )), .little); + try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little); }, else => unreachable, } @@ -201,18 +200,16 @@ pub const StubsHelperSection = struct { try writer.writeInt(i32, @intCast(target - source - 6 - 4), .little); }, .aarch64 => { - const literal = blk: { - const div_res = try std.math.divExact(u64, entry_size - @sizeOf(u32), 4); - break :blk std.math.cast(u18, div_res) orelse return error.Overflow; - }; - try writer.writeInt(u32, aarch64.Instruction.ldrLiteral( - .w16, - literal, - ).toU32(), .little); + const Instruction = aarch64.encoding.Instruction; + if (entry_size % Instruction.size != 0) return error.UnexpectedRemainder; + try writer.writeInt(u32, @bitCast( + Instruction.ldr(.w16, .{ .literal = std.math.cast(i21, entry_size - Instruction.size) orelse + return error.Overflow }), + ), .little); const disp = math.cast(i28, @as(i64, @intCast(target)) - @as(i64, @intCast(source + 4))) orelse return error.Overflow; - try writer.writeInt(u32, aarch64.Instruction.b(disp).toU32(), .little); - try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 }); + try writer.writeInt(u32, @bitCast(Instruction.b(disp)), .little); + try writer.writeInt(u32, @bitCast(Instruction.udf(0x0)), .little); }, else => unreachable, } @@ -242,31 +239,28 @@ pub const StubsHelperSection = struct { try writer.writeByte(0x90); }, .aarch64 => { + const Instruction = aarch64.encoding.Instruction; { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr), @intCast(dyld_private_addr)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); - const off: u12 = @truncate(dyld_private_addr); - try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); + try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x17, pages << 12)), .little); + try writer.writeInt(Instruction.Backing, @bitCast( + Instruction.add(.x17, .x17, .{ .immediate = @as(u12, @truncate(dyld_private_addr)) }), + ), .little); } - try writer.writeInt(u32, aarch64.Instruction.stp( - .x16, - .x17, - aarch64.Register.sp, - aarch64.Instruction.LoadStorePairOffset.pre_index(-16), - ).toU32(), .little); + try writer.writeInt(Instruction.Backing, @bitCast( + Instruction.stp(.x16, .x17, .{ .pre_index = .{ .base = .sp, .index = -16 } }), + ), .little); { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(@intCast(sect.addr + 12), @intCast(dyld_stub_binder_addr)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); - try writer.writeInt(u32, aarch64.Instruction.ldr( - .x16, + try writer.writeInt(Instruction.Backing, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); + try writer.writeInt(Instruction.Backing, @bitCast(Instruction.ldr( .x16, - aarch64.Instruction.LoadStoreOffset.imm(off), - ).toU32(), .little); + .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(dyld_stub_binder_addr)) } }, + )), .little); } - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); + try writer.writeInt(Instruction.Backing, @bitCast(Instruction.br(.x16)), .little); }, else => unreachable, } @@ -426,35 +420,32 @@ pub const ObjcStubsSection = struct { } }, .aarch64 => { + const Instruction = aarch64.encoding.Instruction; { const target = sym.getObjcSelrefsAddress(macho_file); const source = addr; const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); - const off = try math.divExact(u12, @truncate(target), 8); - try writer.writeInt( - u32, - aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), - .little, - ); + try writer.writeInt(u32, @bitCast(Instruction.adrp(.x1, pages << 12)), .little); + try writer.writeInt(u32, @bitCast(Instruction.ldr( + .x1, + .{ .unsigned_offset = .{ .base = .x1, .offset = @as(u12, @truncate(target)) } }, + )), .little); } { const target_sym = obj.getObjcMsgSendRef(macho_file).?.getSymbol(macho_file).?; const target = target_sym.getGotAddress(macho_file); const source = addr + 2 * @sizeOf(u32); const pages = try aarch64.calcNumberOfPages(@intCast(source), @intCast(target)); - try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try math.divExact(u12, @truncate(target), 8); - try writer.writeInt( - u32, - aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), - .little, - ); + try writer.writeInt(u32, @bitCast(Instruction.adrp(.x16, pages << 12)), .little); + try writer.writeInt(u32, @bitCast(Instruction.ldr( + .x16, + .{ .unsigned_offset = .{ .base = .x16, .offset = @as(u12, @truncate(target)) } }, + )), .little); } - try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); - try writer.writeInt(u32, aarch64.Instruction.brk(1).toU32(), .little); + try writer.writeInt(u32, @bitCast(Instruction.br(.x16)), .little); + try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little); + try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little); + try writer.writeInt(u32, @bitCast(Instruction.brk(0x1)), .little); }, else => unreachable, } diff --git a/src/link/aarch64.zig b/src/link/aarch64.zig index d86939a156..c9defc27b3 100644 --- a/src/link/aarch64.zig +++ b/src/link/aarch64.zig @@ -1,66 +1,36 @@ -pub inline fn isArithmeticOp(inst: *const [4]u8) bool { - const group_decode = @as(u5, @truncate(inst[3])); - return ((group_decode >> 2) == 4); -} +pub const encoding = @import("../codegen.zig").aarch64.encoding; pub fn writeAddImmInst(value: u12, code: *[4]u8) void { - var inst = Instruction{ - .add_subtract_immediate = mem.bytesToValue(@FieldType( - Instruction, - @tagName(Instruction.add_subtract_immediate), - ), code), - }; - inst.add_subtract_immediate.imm12 = value; - mem.writeInt(u32, code, inst.toU32(), .little); + var inst: encoding.Instruction = .read(code); + inst.data_processing_immediate.add_subtract_immediate.group.imm12 = value; + inst.write(code); } pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void { - var inst: Instruction = .{ - .load_store_register = mem.bytesToValue(@FieldType( - Instruction, - @tagName(Instruction.load_store_register), - ), code), - }; - inst.load_store_register.offset = value; - mem.writeInt(u32, code, inst.toU32(), .little); + var inst: encoding.Instruction = .read(code); + inst.load_store.register_unsigned_immediate.group.imm12 = value; + inst.write(code); } -pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i21 { - const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow; - const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow; - const pages = math.cast(i21, tpage - spage) orelse return error.Overflow; - return pages; +pub fn calcNumberOfPages(saddr: i64, taddr: i64) error{Overflow}!i33 { + return math.cast(i21, (taddr >> 12) - (saddr >> 12)) orelse error.Overflow; } -pub fn writeAdrpInst(pages: u21, code: *[4]u8) void { - var inst = Instruction{ - .pc_relative_address = mem.bytesToValue(@FieldType( - Instruction, - @tagName(Instruction.pc_relative_address), - ), code), - }; - inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2)); - inst.pc_relative_address.immlo = @as(u2, @truncate(pages)); - mem.writeInt(u32, code, inst.toU32(), .little); +pub fn writeAdrInst(imm: i33, code: *[4]u8) void { + var inst: encoding.Instruction = .read(code); + inst.data_processing_immediate.pc_relative_addressing.group.immhi = @intCast(imm >> 2); + inst.data_processing_immediate.pc_relative_addressing.group.immlo = @bitCast(@as(i2, @truncate(imm))); + inst.write(code); } pub fn writeBranchImm(disp: i28, code: *[4]u8) void { - var inst = Instruction{ - .unconditional_branch_immediate = mem.bytesToValue(@FieldType( - Instruction, - @tagName(Instruction.unconditional_branch_immediate), - ), code), - }; - inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2)))); - mem.writeInt(u32, code, inst.toU32(), .little); + var inst: encoding.Instruction = .read(code); + inst.branch_exception_generating_system.unconditional_branch_immediate.group.imm26 = @intCast(@shrExact(disp, 2)); + inst.write(code); } const assert = std.debug.assert; -const bits = @import("../arch/aarch64/bits.zig"); const builtin = @import("builtin"); const math = std.math; const mem = std.mem; const std = @import("std"); - -pub const Instruction = bits.Instruction; -pub const Register = bits.Register; |
