From 1cf45fb20916568659fcce33dfcfd97013712270 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 5 Mar 2024 23:15:39 +0100 Subject: [PATCH 01/17] elf+aarch64: implement enough to link dynamically with gcc as the driver --- src/link/Elf.zig | 22 ++-- src/link/Elf/LdScript.zig | 1 + src/link/Elf/Object.zig | 11 +- src/link/Elf/Symbol.zig | 3 +- src/link/Elf/eh_frame.zig | 1 + src/link/Elf/synthetic_sections.zig | 150 ++++++++++++++++++++++------ 6 files changed, 137 insertions(+), 51 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1d7dca9517..3c12c40254 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1373,7 +1373,14 @@ pub fn flushModule(self: *Elf, arena: Allocator, prog_node: *std.Progress.Node) try self.writePhdrTable(); try self.writeShdrTable(); try self.writeAtoms(); - try self.writeSyntheticSections(); + self.writeSyntheticSections() catch |err| switch (err) { + error.RelocFailure => return error.FlushFailure, + error.UnsupportedCpuArch => { + try self.reportUnsupportedCpuArch(); + return error.FlushFailure; + }, + else => |e| return e, + }; if (self.entry_index == null and self.base.isExe()) { log.debug("flushing. no_entry_point_found = true", .{}); @@ -4047,7 +4054,7 @@ fn updateSectionSizes(self: *Elf) !void { } if (self.plt_section_index) |index| { - self.shdrs.items[index].sh_size = self.plt.size(); + self.shdrs.items[index].sh_size = self.plt.size(self); } if (self.got_plt_section_index) |index| { @@ -4692,14 +4699,7 @@ fn writeSyntheticSections(self: *Elf) !void { const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); defer buffer.deinit(); - eh_frame.writeEhFrame(self, buffer.writer()) catch |err| switch (err) { - error.RelocFailure => return error.FlushFailure, - error.UnsupportedCpuArch => { - try self.reportUnsupportedCpuArch(); - return error.FlushFailure; - }, - else => |e| return e, - }; + try eh_frame.writeEhFrame(self, buffer.writer()); try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); } @@ -4731,7 +4731,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.plt_section_index) |shndx| { const shdr = self.shdrs.items[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size()); + var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size(self)); defer buffer.deinit(); try self.plt.write(self, buffer.writer()); try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); diff --git a/src/link/Elf/LdScript.zig b/src/link/Elf/LdScript.zig index 34cecf5879..8b48ebd39f 100644 --- a/src/link/Elf/LdScript.zig +++ b/src/link/Elf/LdScript.zig @@ -139,6 +139,7 @@ const Parser = struct { } else return error.UnexpectedToken; }; if (std.mem.eql(u8, value, "elf64-x86-64")) return .x86_64; + if (std.mem.eql(u8, value, "elf64-littleaarch64")) return .aarch64; return error.UnknownCpuArch; } diff --git a/src/link/Elf/Object.zig b/src/link/Elf/Object.zig index d1b35ad286..cc135f2f97 100644 --- a/src/link/Elf/Object.zig +++ b/src/link/Elf/Object.zig @@ -371,17 +371,16 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: const relocs_shndx = for (self.shdrs.items, 0..) |shdr, i| switch (shdr.sh_type) { elf.SHT_RELA => if (shdr.sh_info == shndx) break @as(u32, @intCast(i)), else => {}, - } else { - // TODO: convert into an error - log.debug("{s}: missing reloc section for unwind info section", .{self.fmtPath()}); - return; - }; + } else null; const raw = try self.preadShdrContentsAlloc(allocator, handle, shndx); defer allocator.free(raw); const data_start = @as(u32, @intCast(self.eh_frame_data.items.len)); try self.eh_frame_data.appendSlice(allocator, raw); - const relocs = try self.preadRelocsAlloc(allocator, handle, relocs_shndx); + const relocs = if (relocs_shndx) |index| + try self.preadRelocsAlloc(allocator, handle, index) + else + &[0]elf.Elf64_Rela{}; defer allocator.free(relocs); const rel_start = @as(u32, @intCast(self.relocs.items.len)); try self.relocs.appendUnalignedSlice(allocator, relocs); diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index ea1b4f4b6b..d41307a342 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -146,7 +146,8 @@ pub fn pltAddress(symbol: Symbol, elf_file: *Elf) u64 { if (!symbol.flags.has_plt) return 0; const extras = symbol.extra(elf_file).?; const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?]; - return shdr.sh_addr + extras.plt * 16 + PltSection.preamble_size; + const cpu_arch = elf_file.getTarget().cpu.arch; + return shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch); } pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) u64 { diff --git a/src/link/Elf/eh_frame.zig b/src/link/Elf/eh_frame.zig index 048d4c6d5c..3b4668da1d 100644 --- a/src/link/Elf/eh_frame.zig +++ b/src/link/Elf/eh_frame.zig @@ -214,6 +214,7 @@ pub const Iterator = struct { const reader = stream.reader(); const size = try reader.readInt(u32, .little); + if (size == 0) return null; if (size == 0xFFFFFFFF) @panic("TODO"); const id = try reader.readInt(u32, .little); diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 506f4394b3..abedf72aaf 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -857,8 +857,6 @@ pub const PltSection = struct { symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, output_symtab_ctx: Elf.SymtabCtx = .{}, - pub const preamble_size = 32; - pub fn deinit(plt: *PltSection, allocator: Allocator) void { plt.symbols.deinit(allocator); } @@ -877,39 +875,33 @@ pub const PltSection = struct { try plt.symbols.append(gpa, sym_index); } - pub fn size(plt: PltSection) usize { - return preamble_size + plt.symbols.items.len * 16; + pub fn size(plt: PltSection, elf_file: *Elf) usize { + const cpu_arch = elf_file.getTarget().cpu.arch; + return preambleSize(cpu_arch) + plt.symbols.items.len * entrySize(cpu_arch); + } + + pub fn preambleSize(cpu_arch: std.Target.Cpu.Arch) usize { + return switch (cpu_arch) { + .x86_64 => 32, + .aarch64 => 8 * @sizeOf(u32), + else => @panic("TODO implement preambleSize for this cpu arch"), + }; + } + + pub fn entrySize(cpu_arch: std.Target.Cpu.Arch) usize { + return switch (cpu_arch) { + .x86_64 => 16, + .aarch64 => 4 * @sizeOf(u32), + else => @panic("TODO implement entrySize for this cpu arch"), + }; } pub fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { - const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; - const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; - var preamble = [_]u8{ - 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 - 0x41, 0x53, // push r11 - 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push qword ptr [rip] -> .got.plt[1] - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[2] - }; - var disp = @as(i64, @intCast(got_plt_addr + 8)) - @as(i64, @intCast(plt_addr + 8)) - 4; - mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); - disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; - mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); - try writer.writeAll(&preamble); - try writer.writeByteNTimes(0xcc, preamble_size - preamble.len); - - for (plt.symbols.items, 0..) |sym_index, i| { - const sym = elf_file.symbol(sym_index); - const target_addr = sym.gotPltAddress(elf_file); - const source_addr = sym.pltAddress(elf_file); - disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; - var entry = [_]u8{ - 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 - 0x41, 0xbb, 0x00, 0x00, 0x00, 0x00, // mov r11d, N - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[N] - }; - mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(i)), .little); - mem.writeInt(i32, entry[12..][0..4], @as(i32, @intCast(disp)), .little); - try writer.writeAll(&entry); + const cpu_arch = elf_file.getTarget().cpu.arch; + switch (cpu_arch) { + .x86_64 => try x86_64.write(plt, elf_file, writer), + .aarch64 => try aarch64.write(plt, elf_file, writer), + else => return error.UnsupportedCpuArch, } } @@ -946,6 +938,7 @@ pub const PltSection = struct { } pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void { + const cpu_arch = elf_file.getTarget().cpu.arch; for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| { const sym = elf_file.symbol(sym_index); const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); @@ -958,7 +951,7 @@ pub const PltSection = struct { .st_other = 0, .st_shndx = @intCast(elf_file.plt_section_index.?), .st_value = sym.pltAddress(elf_file), - .st_size = 16, + .st_size = entrySize(cpu_arch), }; } } @@ -992,6 +985,97 @@ pub const PltSection = struct { }); } } + + const x86_64 = struct { + fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { + const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; + const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].sh_addr; + var preamble = [_]u8{ + 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 + 0x41, 0x53, // push r11 + 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // push qword ptr [rip] -> .got.plt[1] + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[2] + }; + var disp = @as(i64, @intCast(got_plt_addr + 8)) - @as(i64, @intCast(plt_addr + 8)) - 4; + mem.writeInt(i32, preamble[8..][0..4], @as(i32, @intCast(disp)), .little); + disp = @as(i64, @intCast(got_plt_addr + 16)) - @as(i64, @intCast(plt_addr + 14)) - 4; + mem.writeInt(i32, preamble[14..][0..4], @as(i32, @intCast(disp)), .little); + try writer.writeAll(&preamble); + try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len); + + for (plt.symbols.items, 0..) |sym_index, i| { + const sym = elf_file.symbol(sym_index); + const target_addr = sym.gotPltAddress(elf_file); + const source_addr = sym.pltAddress(elf_file); + disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4; + var entry = [_]u8{ + 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 + 0x41, 0xbb, 0x00, 0x00, 0x00, 0x00, // mov r11d, N + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got.plt[N] + }; + mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(i)), .little); + mem.writeInt(i32, entry[12..][0..4], @as(i32, @intCast(disp)), .little); + try writer.writeAll(&entry); + } + } + }; + + const aarch64 = struct { + fn write(plt: PltSection, elf_file: *Elf, writer: anytype) !void { + { + const plt_addr = elf_file.shdrs.items[elf_file.plt_section_index.?].sh_addr; + const got_plt_addr = elf_file.shdrs.items[elf_file.got_plt_section_index.?].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 aarch64_util.calcPageOffset(.load_store_64, got_plt_addr + 16); + const add_off = try aarch64_util.calcPageOffset(.arithmetic, 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(), + }; + comptime assert(preamble.len == 8); + for (preamble) |inst| { + try writer.writeInt(u32, inst.toU32(), .little); + } + } + + for (plt.symbols.items) |sym_index| { + const sym = elf_file.symbol(sym_index); + 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 aarch64_util.calcPageOffset(.load_store_64, target_addr); + const add_off = try aarch64_util.calcPageOffset(.arithmetic, 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), + }; + comptime assert(insts.len == 4); + for (insts) |inst| { + try writer.writeInt(u32, inst.toU32(), .little); + } + } + } + + const aarch64_util = @import("../aarch64.zig"); + const Instruction = aarch64_util.Instruction; + const Register = aarch64_util.Register; + }; }; pub const GotPltSection = struct { From 0af5d2e9b6393de460106f9f53a68374e636087a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 7 Mar 2024 22:46:07 +0100 Subject: [PATCH 02/17] elf+aarch64: implement .plt.got --- src/link/Elf.zig | 4 +- src/link/Elf/Symbol.zig | 4 +- src/link/Elf/synthetic_sections.zig | 73 +++++++++++++++++++++++------ 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 3c12c40254..ce4075a0ea 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -4062,7 +4062,7 @@ fn updateSectionSizes(self: *Elf) !void { } if (self.plt_got_section_index) |index| { - self.shdrs.items[index].sh_size = self.plt_got.size(); + self.shdrs.items[index].sh_size = self.plt_got.size(self); } if (self.rela_dyn_section_index) |shndx| { @@ -4747,7 +4747,7 @@ fn writeSyntheticSections(self: *Elf) !void { if (self.plt_got_section_index) |shndx| { const shdr = self.shdrs.items[shndx]; - var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size()); + var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size(self)); defer buffer.deinit(); try self.plt_got.write(self, buffer.writer()); try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index d41307a342..59f19b74f9 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -139,7 +139,8 @@ pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) u64 { if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0; const extras = symbol.extra(elf_file).?; const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?]; - return shdr.sh_addr + extras.plt_got * 16; + const cpu_arch = elf_file.getTarget().cpu.arch; + return shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch); } pub fn pltAddress(symbol: Symbol, elf_file: *Elf) u64 { @@ -442,6 +443,7 @@ const GotPltSection = synthetic_sections.GotPltSection; const LinkerDefined = @import("LinkerDefined.zig"); const Object = @import("Object.zig"); const PltSection = synthetic_sections.PltSection; +const PltGotSection = synthetic_sections.PltGotSection; const SharedObject = @import("SharedObject.zig"); const Symbol = @This(); const ZigGotSection = synthetic_sections.ZigGotSection; diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index abedf72aaf..289c22d61f 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -1130,23 +1130,24 @@ pub const PltGotSection = struct { try plt_got.symbols.append(gpa, sym_index); } - pub fn size(plt_got: PltGotSection) usize { - return plt_got.symbols.items.len * 16; + pub fn size(plt_got: PltGotSection, elf_file: *Elf) usize { + return plt_got.symbols.items.len * entrySize(elf_file.getTarget().cpu.arch); + } + + pub fn entrySize(cpu_arch: std.Target.Cpu.Arch) usize { + return switch (cpu_arch) { + .x86_64 => 16, + .aarch64 => 4 * @sizeOf(u32), + else => @panic("TODO implement PltGotSection.entrySize for this arch"), + }; } pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { - for (plt_got.symbols.items) |sym_index| { - const sym = elf_file.symbol(sym_index); - const target_addr = sym.gotAddress(elf_file); - const source_addr = sym.pltGotAddress(elf_file); - const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4; - var entry = [_]u8{ - 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 - 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got[N] - 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, - }; - mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(disp)), .little); - try writer.writeAll(&entry); + const cpu_arch = elf_file.getTarget().cpu.arch; + switch (cpu_arch) { + .x86_64 => try x86_64.write(plt_got, elf_file, writer), + .aarch64 => try aarch64.write(plt_got, elf_file, writer), + else => return error.UnsupportedCpuArch, } } @@ -1175,6 +1176,50 @@ pub const PltGotSection = struct { }; } } + + const x86_64 = struct { + pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { + for (plt_got.symbols.items) |sym_index| { + const sym = elf_file.symbol(sym_index); + const target_addr = sym.gotAddress(elf_file); + const source_addr = sym.pltGotAddress(elf_file); + const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4; + var entry = [_]u8{ + 0xf3, 0x0f, 0x1e, 0xfa, // endbr64 + 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip] -> .got[N] + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + }; + mem.writeInt(i32, entry[6..][0..4], @as(i32, @intCast(disp)), .little); + try writer.writeAll(&entry); + } + } + }; + + const aarch64 = struct { + fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void { + for (plt_got.symbols.items) |sym_index| { + const sym = elf_file.symbol(sym_index); + 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 aarch64_util.calcPageOffset(.load_store_64, target_addr); + const insts = &[_]Instruction{ + Instruction.adrp(.x16, pages), + Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), + Instruction.br(.x17), + Instruction.nop(), + }; + comptime assert(insts.len == 4); + for (insts) |inst| { + try writer.writeInt(u32, inst.toU32(), .little); + } + } + } + + const aarch64_util = @import("../aarch64.zig"); + const Instruction = aarch64_util.Instruction; + const Register = aarch64_util.Register; + }; }; pub const CopyRelSection = struct { From 69f9f359dd5107cd071f3801a6824336b5d2bce6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 7 Mar 2024 22:55:15 +0100 Subject: [PATCH 03/17] elf+aarch64: use correctly offset tp address --- src/link/Elf.zig | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ce4075a0ea..12f02f9761 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -5572,11 +5572,17 @@ pub fn gotAddress(self: *Elf) u64 { pub fn tpAddress(self: *Elf) u64 { const index = self.phdr_tls_index orelse return 0; const phdr = self.phdrs.items[index]; - return mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align); + return switch (self.getTarget().cpu.arch) { + .x86_64 => mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align), + .aarch64 => mem.alignBackward(u64, phdr.p_vaddr - 16, phdr.p_align), + else => @panic("TODO implement getTpAddress for this arch"), + }; } pub fn dtpAddress(self: *Elf) u64 { - return self.tlsAddress(); + const index = self.phdr_tls_index orelse return 0; + const phdr = self.phdrs.items[index]; + return phdr.p_vaddr; } pub fn tlsAddress(self: *Elf) u64 { From c1dbf01aa3e7ee1922762e6f9b86b2ad4c4a7e6f Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 7 Mar 2024 23:01:06 +0100 Subject: [PATCH 04/17] elf+aarch64: resolve TLS LE model --- src/link/Elf/Atom.zig | 20 +++++++++++++++++++- src/link/aarch64.zig | 11 +++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 5dc5835c9f..71f9d79fac 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1592,6 +1592,8 @@ const aarch64 = struct { _ = it; const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + const is_dyn_lib = elf_file.base.isDynLib(); + switch (r_type) { .ABS64 => { try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); @@ -1629,6 +1631,12 @@ const aarch64 = struct { .LDST128_ABS_LO12_NC, => {}, + .TLSLE_ADD_TPREL_HI12, + .TLSLE_ADD_TPREL_LO12_NC, + => { + if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); + }, + else => try atom.reportUnhandledRelocError(rel, elf_file), } } @@ -1650,7 +1658,6 @@ const aarch64 = struct { const cwriter = stream.writer(); const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; - _ = TP; _ = DTP; _ = ZIG_GOT; @@ -1736,6 +1743,17 @@ const aarch64 = struct { try aarch64_util.writePageOffset(kind, taddr, code[r_offset..][0..4]); }, + .TLSLE_ADD_TPREL_HI12 => { + const value = math.cast(i12, (S + A - TP) >> 12) orelse + return error.Overflow; + try aarch64_util.writeAddInst(@bitCast(value), code[rel.r_offset..][0..4]); + }, + + .TLSLE_ADD_TPREL_LO12_NC => { + const value: i12 = @truncate(S + A - TP); + try aarch64_util.writeAddInst(@bitCast(value), code[rel.r_offset..][0..4]); + }, + else => try atom.reportUnhandledRelocError(rel, elf_file), } } diff --git a/src/link/aarch64.zig b/src/link/aarch64.zig index a9295026d2..273dee7493 100644 --- a/src/link/aarch64.zig +++ b/src/link/aarch64.zig @@ -95,6 +95,17 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) !void { mem.writeInt(u32, code, inst.toU32(), .little); } +pub fn writeAddInst(value: u12, code: *[4]u8) !void { + var inst = Instruction{ + .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( + Instruction, + Instruction.add_subtract_immediate, + ), code), + }; + inst.add_subtract_immediate.imm12 = value; + mem.writeInt(u32, code, inst.toU32(), .little); +} + const assert = std.debug.assert; const bits = @import("../arch/aarch64/bits.zig"); const builtin = @import("builtin"); From 109d2321b0d92f20e75dcc0b7074026cefe1090e Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:13:30 +0100 Subject: [PATCH 05/17] link: refactor common aarch64 helpers --- src/link/Elf/Atom.zig | 33 ++++++------ src/link/Elf/synthetic_sections.zig | 11 ++-- src/link/MachO/Atom.zig | 32 ++++++++--- src/link/MachO/synthetic.zig | 10 ++-- src/link/MachO/thunks.zig | 2 +- src/link/aarch64.zig | 83 ++++++----------------------- 6 files changed, 71 insertions(+), 100 deletions(-) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 71f9d79fac..9a896c1396 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1689,7 +1689,7 @@ const aarch64 = struct { }); return; }; - try aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]); + aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]); }, .ADR_PREL_PG_HI21 => { @@ -1697,14 +1697,14 @@ const aarch64 = struct { const saddr = @as(u64, @intCast(P)); const taddr = @as(u64, @intCast(S + A)); const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); - try aarch64_util.writePages(pages, code[r_offset..][0..4]); + aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]); }, .ADR_GOT_PAGE => if (target.flags.has_got) { const saddr = @as(u64, @intCast(P)); const taddr = @as(u64, @intCast(G + GOT + A)); const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); - try aarch64_util.writePages(pages, code[r_offset..][0..4]); + aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]); } else { // TODO: relax var err = try elf_file.addErrorWithNotes(1); @@ -1719,10 +1719,14 @@ const aarch64 = struct { .LD64_GOT_LO12_NC => { assert(target.flags.has_got); const taddr = @as(u64, @intCast(G + GOT + A)); - try aarch64_util.writePageOffset(.load_store_64, taddr, code[r_offset..][0..4]); + aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code[rel.r_offset..][0..4]); + }, + + .ADD_ABS_LO12_NC => { + const taddr = @as(u64, @intCast(S + A)); + aarch64_util.writeAddImmInst(@truncate(taddr), code[rel.r_offset..][0..4]); }, - .ADD_ABS_LO12_NC, .LDST8_ABS_LO12_NC, .LDST16_ABS_LO12_NC, .LDST32_ABS_LO12_NC, @@ -1731,27 +1735,26 @@ const aarch64 = struct { => { // TODO: NC means no overflow check const taddr = @as(u64, @intCast(S + A)); - const kind: aarch64_util.PageOffsetInstKind = switch (r_type) { - .ADD_ABS_LO12_NC => .arithmetic, - .LDST8_ABS_LO12_NC => .load_store_8, - .LDST16_ABS_LO12_NC => .load_store_16, - .LDST32_ABS_LO12_NC => .load_store_32, - .LDST64_ABS_LO12_NC => .load_store_64, - .LDST128_ABS_LO12_NC => .load_store_128, + const offset: u12 = switch (r_type) { + .LDST8_ABS_LO12_NC => @truncate(taddr), + .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2), + .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4), + .LDST64_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 8), + .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), else => unreachable, }; - try aarch64_util.writePageOffset(kind, taddr, code[r_offset..][0..4]); + aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]); }, .TLSLE_ADD_TPREL_HI12 => { const value = math.cast(i12, (S + A - TP) >> 12) orelse return error.Overflow; - try aarch64_util.writeAddInst(@bitCast(value), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); }, .TLSLE_ADD_TPREL_LO12_NC => { const value: i12 = @truncate(S + A - TP); - try aarch64_util.writeAddInst(@bitCast(value), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); }, else => try atom.reportUnhandledRelocError(rel, elf_file), diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 289c22d61f..04a3793561 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -1028,8 +1028,8 @@ pub const PltSection = struct { // TODO: relax if possible // .got.plt[2] const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16); - const ldr_off = try aarch64_util.calcPageOffset(.load_store_64, got_plt_addr + 16); - const add_off = try aarch64_util.calcPageOffset(.arithmetic, got_plt_addr + 16); + const ldr_off = try math.divExact(u12, @truncate(got_plt_addr + 16), 8); + const add_off: u12 = @truncate(got_plt_addr + 16); const preamble = &[_]Instruction{ Instruction.stp( @@ -1057,8 +1057,8 @@ pub const PltSection = struct { 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 aarch64_util.calcPageOffset(.load_store_64, target_addr); - const add_off = try aarch64_util.calcPageOffset(.arithmetic, target_addr); + const ldr_off = try math.divExact(u12, @truncate(target_addr), 8); + const add_off: u12 = @truncate(target_addr); const insts = &[_]Instruction{ Instruction.adrp(.x16, pages), Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)), @@ -1202,7 +1202,7 @@ pub const PltGotSection = struct { 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 aarch64_util.calcPageOffset(.load_store_64, target_addr); + const off = try math.divExact(u12, @truncate(target_addr), 8); const insts = &[_]Instruction{ Instruction.adrp(.x16, pages), Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)), @@ -1758,6 +1758,7 @@ fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void { const assert = std.debug.assert; const builtin = @import("builtin"); const elf = std.elf; +const math = std.math; const mem = std.mem; const log = std.log.scoped(.link); const relocation = @import("relocation.zig"); diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index d40712046e..b4600176ce 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -700,7 +700,7 @@ fn resolveRelocInner( const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file)); break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; - try aarch64.writeBranchImm(disp, code[rel_offset..][0..4]); + aarch64.writeBranchImm(disp, code[rel_offset..][0..4]); }, else => unreachable, } @@ -771,7 +771,7 @@ fn resolveRelocInner( break :target math.cast(u64, target) orelse return error.Overflow; }; const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(source, target))); - try aarch64.writePages(pages, code[rel_offset..][0..4]); + aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]); }, .pageoff => { @@ -780,8 +780,26 @@ fn resolveRelocInner( assert(!rel.meta.pcrel); const target = math.cast(u64, S + A) orelse return error.Overflow; const inst_code = code[rel_offset..][0..4]; - const kind = aarch64.classifyInst(inst_code); - try aarch64.writePageOffset(kind, target, inst_code); + if (aarch64.isArithmeticOp(inst_code)) { + aarch64.writeAddImmInst(@truncate(target), inst_code); + } else { + var inst = aarch64.Instruction{ + .load_store_register = mem.bytesToValue(std.meta.TagPayload( + aarch64.Instruction, + 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 math.divExact(u12, @truncate(target), 16) + else + @truncate(target), + 1 => try math.divExact(u12, @truncate(target), 2), + 2 => try math.divExact(u12, @truncate(target), 4), + 3 => try math.divExact(u12, @truncate(target), 8), + }; + try writer.writeInt(u32, inst.toU32(), .little); + } }, .got_load_pageoff => { @@ -789,7 +807,7 @@ fn resolveRelocInner( assert(rel.meta.length == 2); assert(!rel.meta.pcrel); const target = math.cast(u64, G + A) orelse return error.Overflow; - try aarch64.writePageOffset(.load_store_64, target, code[rel_offset..][0..4]); + aarch64.writeLoadStoreRegInst(try math.divExact(u12, @truncate(target), 8), code[rel_offset..][0..4]); }, .tlvp_pageoff => { @@ -841,7 +859,7 @@ fn resolveRelocInner( .load_store_register = .{ .rt = reg_info.rd, .rn = reg_info.rn, - .offset = try aarch64.calcPageOffset(.load_store_64, target), + .offset = try math.divExact(u12, @truncate(target), 8), .opc = 0b01, .op1 = 0b01, .v = 0, @@ -851,7 +869,7 @@ fn resolveRelocInner( .add_subtract_immediate = .{ .rd = reg_info.rd, .rn = reg_info.rn, - .imm12 = try aarch64.calcPageOffset(.arithmetic, target), + .imm12 = @truncate(target), .sh = 0, .s = 0, .op = 0, diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index 0536026633..1afbd3ea6d 100644 --- a/src/link/MachO/synthetic.zig +++ b/src/link/MachO/synthetic.zig @@ -269,7 +269,7 @@ pub const StubsSection = struct { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(source, target); try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try aarch64.calcPageOffset(.load_store_64, target); + const off = try math.divExact(u12, @truncate(target), 8); try writer.writeInt( u32, aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), @@ -413,7 +413,7 @@ pub const StubsHelperSection = struct { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(sect.addr, dyld_private_addr); try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little); - const off = try aarch64.calcPageOffset(.arithmetic, dyld_private_addr); + const off: u12 = @truncate(dyld_private_addr); try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little); } try writer.writeInt(u32, aarch64.Instruction.stp( @@ -426,7 +426,7 @@ pub const StubsHelperSection = struct { // TODO relax if possible const pages = try aarch64.calcNumberOfPages(sect.addr + 12, dyld_stub_binder_addr); try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try aarch64.calcPageOffset(.load_store_64, dyld_stub_binder_addr); + const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8); try writer.writeInt(u32, aarch64.Instruction.ldr( .x16, .x16, @@ -681,7 +681,7 @@ pub const ObjcStubsSection = struct { const source = addr; const pages = try aarch64.calcNumberOfPages(source, target); try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little); - const off = try aarch64.calcPageOffset(.load_store_64, target); + const off = try math.divExact(u12, @truncate(target), 8); try writer.writeInt( u32, aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), @@ -694,7 +694,7 @@ pub const ObjcStubsSection = struct { const source = addr + 2 * @sizeOf(u32); const pages = try aarch64.calcNumberOfPages(source, target); try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try aarch64.calcPageOffset(.load_store_64, target); + const off = try math.divExact(u12, @truncate(target), 8); try writer.writeInt( u32, aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(), diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig index e3f98c655c..02dacc1aec 100644 --- a/src/link/MachO/thunks.zig +++ b/src/link/MachO/thunks.zig @@ -101,7 +101,7 @@ pub const Thunk = struct { const taddr = sym.getAddress(.{}, macho_file); const pages = try aarch64.calcNumberOfPages(saddr, taddr); try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little); - const off = try aarch64.calcPageOffset(.arithmetic, taddr); + 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); } diff --git a/src/link/aarch64.zig b/src/link/aarch64.zig index 273dee7493..576249e988 100644 --- a/src/link/aarch64.zig +++ b/src/link/aarch64.zig @@ -3,66 +3,26 @@ pub inline fn isArithmeticOp(inst: *const [4]u8) bool { return ((group_decode >> 2) == 4); } -pub const PageOffsetInstKind = enum { - arithmetic, - load_store_8, - load_store_16, - load_store_32, - load_store_64, - load_store_128, -}; +pub fn writeAddImmInst(value: u12, code: *[4]u8) void { + var inst = Instruction{ + .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( + Instruction, + Instruction.add_subtract_immediate, + ), code), + }; + inst.add_subtract_immediate.imm12 = value; + mem.writeInt(u32, code, inst.toU32(), .little); +} -pub fn classifyInst(code: *const [4]u8) PageOffsetInstKind { - if (isArithmeticOp(code)) return .arithmetic; - const inst = Instruction{ +pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void { + var inst: Instruction = .{ .load_store_register = mem.bytesToValue(std.meta.TagPayload( Instruction, Instruction.load_store_register, ), code), }; - return switch (inst.load_store_register.size) { - 0 => if (inst.load_store_register.v == 1) .load_store_128 else .load_store_8, - 1 => .load_store_16, - 2 => .load_store_32, - 3 => .load_store_64, - }; -} - -pub fn calcPageOffset(kind: PageOffsetInstKind, taddr: u64) !u12 { - const narrowed = @as(u12, @truncate(taddr)); - return switch (kind) { - .arithmetic, .load_store_8 => narrowed, - .load_store_16 => try math.divExact(u12, narrowed, 2), - .load_store_32 => try math.divExact(u12, narrowed, 4), - .load_store_64 => try math.divExact(u12, narrowed, 8), - .load_store_128 => try math.divExact(u12, narrowed, 16), - }; -} - -pub fn writePageOffset(kind: PageOffsetInstKind, taddr: u64, code: *[4]u8) !void { - const value = try calcPageOffset(kind, taddr); - switch (kind) { - .arithmetic => { - var inst = Instruction{ - .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( - Instruction, - Instruction.add_subtract_immediate, - ), code), - }; - inst.add_subtract_immediate.imm12 = value; - mem.writeInt(u32, code, inst.toU32(), .little); - }, - else => { - var inst: Instruction = .{ - .load_store_register = mem.bytesToValue(std.meta.TagPayload( - Instruction, - Instruction.load_store_register, - ), code), - }; - inst.load_store_register.offset = value; - mem.writeInt(u32, code, inst.toU32(), .little); - }, - } + inst.load_store_register.offset = value; + mem.writeInt(u32, code, inst.toU32(), .little); } pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 { @@ -72,7 +32,7 @@ pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 { return pages; } -pub fn writePages(pages: u21, code: *[4]u8) !void { +pub fn writeAdrpInst(pages: u21, code: *[4]u8) void { var inst = Instruction{ .pc_relative_address = mem.bytesToValue(std.meta.TagPayload( Instruction, @@ -84,7 +44,7 @@ pub fn writePages(pages: u21, code: *[4]u8) !void { mem.writeInt(u32, code, inst.toU32(), .little); } -pub fn writeBranchImm(disp: i28, code: *[4]u8) !void { +pub fn writeBranchImm(disp: i28, code: *[4]u8) void { var inst = Instruction{ .unconditional_branch_immediate = mem.bytesToValue(std.meta.TagPayload( Instruction, @@ -95,17 +55,6 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) !void { mem.writeInt(u32, code, inst.toU32(), .little); } -pub fn writeAddInst(value: u12, code: *[4]u8) !void { - var inst = Instruction{ - .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( - Instruction, - Instruction.add_subtract_immediate, - ), code), - }; - inst.add_subtract_immediate.imm12 = value; - mem.writeInt(u32, code, inst.toU32(), .little); -} - const assert = std.debug.assert; const bits = @import("../arch/aarch64/bits.zig"); const builtin = @import("builtin"); From 310cef09724067f4df38b42c928cb120fdc09df8 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:20:35 +0100 Subject: [PATCH 06/17] elf+aarch64: handle TLSDESC non-relaxed --- src/link/Elf.zig | 3 +-- src/link/Elf/Atom.zig | 53 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 12f02f9761..78cc434b2f 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2105,7 +2105,6 @@ fn scanRelocs(self: *Elf) !void { } if (sym.flags.needs_tlsdesc) { log.debug("'{s}' needs TLSDESC", .{sym.name(self)}); - try self.dynsym.addSymbol(index, self); try self.got.addTlsDescSymbol(index, self); } } @@ -4497,7 +4496,7 @@ fn writeAtoms(self: *Elf) !void { const buffer = try gpa.alloc(u8, sh_size); defer gpa.free(buffer); const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and - shdr.sh_flags & elf.SHF_EXECINSTR != 0) + shdr.sh_flags & elf.SHF_EXECINSTR != 0 and self.getTarget().cpu.arch == .x86_64) 0xcc // int3 else 0; diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 9a896c1396..00cf419f60 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1622,6 +1622,22 @@ const aarch64 = struct { } }, + .TLSLE_ADD_TPREL_HI12, + .TLSLE_ADD_TPREL_LO12_NC, + => { + if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); + }, + + .TLSDESC_ADR_PAGE21, + .TLSDESC_LD64_LO12, + .TLSDESC_ADD_LO12, + => { + const should_relax = elf_file.base.isStatic() or (!is_dyn_lib and !symbol.flags.import); + if (!should_relax and true) { // TODO + symbol.flags.needs_tlsdesc = true; + } + }, + .ADD_ABS_LO12_NC, .ADR_PREL_LO21, .LDST8_ABS_LO12_NC, @@ -1629,14 +1645,9 @@ const aarch64 = struct { .LDST32_ABS_LO12_NC, .LDST64_ABS_LO12_NC, .LDST128_ABS_LO12_NC, + .TLSDESC_CALL, => {}, - .TLSLE_ADD_TPREL_HI12, - .TLSLE_ADD_TPREL_LO12_NC, - => { - if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); - }, - else => try atom.reportUnhandledRelocError(rel, elf_file), } } @@ -1757,6 +1768,36 @@ const aarch64 = struct { aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); }, + .TLSDESC_ADR_PAGE21 => { + assert(target.flags.has_tlsdesc); // TODO relax + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const saddr: u64 = @intCast(P); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); + aarch64_util.writeAdrpInst(pages, code[rel.r_offset..][0..4]); + }, + + .TLSDESC_LD64_LO12 => { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); + aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]); + }, + + .TLSDESC_ADD_LO12 => { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = @truncate(taddr); + aarch64_util.writeAddImmInst(offset, code[rel.r_offset..][0..4]); + }, + + .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { + mem.writeInt(u32, code[rel.r_offset..][0..4], aarch64_util.Instruction.nop().toU32(), .little); + }, + else => try atom.reportUnhandledRelocError(rel, elf_file), } } From d9069cbe2cf88634eb556b3063ede5af4a5cced4 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:30:06 +0100 Subject: [PATCH 07/17] elf+aarch64: relax TLSDESC for executables --- src/link/Elf/Atom.zig | 90 +++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 28 deletions(-) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 00cf419f60..fca2fbef27 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1633,7 +1633,7 @@ const aarch64 = struct { .TLSDESC_ADD_LO12, => { const should_relax = elf_file.base.isStatic() or (!is_dyn_lib and !symbol.flags.import); - if (!should_relax and true) { // TODO + if (!should_relax) { symbol.flags.needs_tlsdesc = true; } }, @@ -1659,7 +1659,7 @@ const aarch64 = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - code: []u8, + code_buffer: []u8, stream: anytype, ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void { _ = it; @@ -1667,6 +1667,7 @@ const aarch64 = struct { const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); + const code = code_buffer[rel.r_offset..][0..4]; const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; _ = DTP; @@ -1700,7 +1701,7 @@ const aarch64 = struct { }); return; }; - aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]); + aarch64_util.writeBranchImm(disp, code); }, .ADR_PREL_PG_HI21 => { @@ -1708,14 +1709,14 @@ const aarch64 = struct { const saddr = @as(u64, @intCast(P)); const taddr = @as(u64, @intCast(S + A)); const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); - aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]); + aarch64_util.writeAdrpInst(pages, code); }, .ADR_GOT_PAGE => if (target.flags.has_got) { const saddr = @as(u64, @intCast(P)); const taddr = @as(u64, @intCast(G + GOT + A)); const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); - aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]); + aarch64_util.writeAdrpInst(pages, code); } else { // TODO: relax var err = try elf_file.addErrorWithNotes(1); @@ -1730,12 +1731,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[rel.r_offset..][0..4]); + aarch64_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[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@truncate(taddr), code); }, .LDST8_ABS_LO12_NC, @@ -1754,48 +1755,79 @@ const aarch64 = struct { .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), else => unreachable, }; - aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]); + aarch64_util.writeLoadStoreRegInst(offset, code); }, .TLSLE_ADD_TPREL_HI12 => { const value = math.cast(i12, (S + A - TP) >> 12) orelse return error.Overflow; - aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@bitCast(value), code); }, .TLSLE_ADD_TPREL_LO12_NC => { const value: i12 = @truncate(S + A - TP); - aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@bitCast(value), code); }, .TLSDESC_ADR_PAGE21 => { - assert(target.flags.has_tlsdesc); // TODO relax - const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); - const saddr: u64 = @intCast(P); - const taddr: u64 = @intCast(S_ + A); - relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); - const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); - aarch64_util.writeAdrpInst(pages, code[rel.r_offset..][0..4]); + if (target.flags.has_tlsdesc) { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const saddr: u64 = @intCast(P); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); + aarch64_util.writeAdrpInst(pages, code); + } else { + relocs_log.debug(" relaxing adrp => nop", .{}); + mem.writeInt(u32, code, Instruction.nop().toU32(), .little); + } }, .TLSDESC_LD64_LO12 => { - const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); - const taddr: u64 = @intCast(S_ + A); - relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); - const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); - aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]); + if (target.flags.has_tlsdesc) { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); + aarch64_util.writeLoadStoreRegInst(offset, code); + } else { + relocs_log.debug(" relaxing ldr => nop", .{}); + mem.writeInt(u32, code, Instruction.nop().toU32(), .little); + } }, .TLSDESC_ADD_LO12 => { - const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); - const taddr: u64 = @intCast(S_ + A); - relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); - const offset: u12 = @truncate(taddr); - aarch64_util.writeAddImmInst(offset, code[rel.r_offset..][0..4]); + if (target.flags.has_tlsdesc) { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = @truncate(taddr); + aarch64_util.writeAddImmInst(offset, code); + } else { + const old_inst = Instruction{ + .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( + Instruction, + 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 }); + 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); + } }, .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { - mem.writeInt(u32, code[rel.r_offset..][0..4], aarch64_util.Instruction.nop().toU32(), .little); + const old_inst = Instruction{ + .unconditional_branch_register = mem.bytesToValue(std.meta.TagPayload( + Instruction, + 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 }); + const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); + mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little); }, else => try atom.reportUnhandledRelocError(rel, elf_file), @@ -1830,6 +1862,8 @@ const aarch64 = struct { } const aarch64_util = @import("../aarch64.zig"); + const Instruction = aarch64_util.Instruction; + const Register = aarch64_util.Register; }; const riscv = struct { From b5642b4f85e7962ee7eb3d137e47fadf392a865b Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:32:47 +0100 Subject: [PATCH 08/17] elf+aarch64: set _GLOBAL_OFFSET_TABLE_ to .got section --- src/link/Elf.zig | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 78cc434b2f..b18e97a556 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -3170,11 +3170,20 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { } // _GLOBAL_OFFSET_TABLE_ - if (self.got_plt_section_index) |shndx| { - const shdr = &self.shdrs.items[shndx]; - const symbol_ptr = self.symbol(self.got_index.?); - symbol_ptr.value = shdr.sh_addr; - symbol_ptr.output_section_index = shndx; + if (self.getTarget().cpu.arch == .x86_64) { + if (self.got_plt_section_index) |shndx| { + const shdr = self.shdrs.items[shndx]; + const sym = self.symbol(self.got_index.?); + sym.value = shdr.sh_addr; + sym.output_section_index = shndx; + } + } else { + if (self.got_section_index) |shndx| { + const shdr = self.shdrs.items[shndx]; + const sym = self.symbol(self.got_index.?); + sym.value = shdr.sh_addr; + sym.output_section_index = shndx; + } } // _PROCEDURE_LINKAGE_TABLE_ From 7258d143e355f6bd92797cdb193c2b1ad2a1650d Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:38:21 +0100 Subject: [PATCH 09/17] elf+aarch64: fix incorrectly emitted TLSDESC relocs --- src/link/Elf/synthetic_sections.zig | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/link/Elf/synthetic_sections.zig b/src/link/Elf/synthetic_sections.zig index 04a3793561..b55e5de432 100644 --- a/src/link/Elf/synthetic_sections.zig +++ b/src/link/Elf/synthetic_sections.zig @@ -634,8 +634,17 @@ pub const GotSection = struct { } }, .tlsdesc => { - try writeInt(0, elf_file, writer); - try writeInt(0, elf_file, writer); + if (symbol.?.flags.import) { + try writeInt(0, elf_file, writer); + try writeInt(0, elf_file, writer); + } else { + try writeInt(0, elf_file, writer); + const offset = if (apply_relocs) + @as(i64, @intCast(symbol.?.address(.{}, elf_file))) - @as(i64, @intCast(elf_file.tlsAddress())) + else + 0; + try writeInt(offset, elf_file, writer); + } }, } } @@ -738,8 +747,9 @@ pub const GotSection = struct { const offset = symbol.?.tlsDescAddress(elf_file); elf_file.addRelaDynAssumeCapacity(.{ .offset = offset, - .sym = extra.?.dynamic, + .sym = if (symbol.?.flags.import) extra.?.dynamic else 0, .type = relocation.encode(.tlsdesc, cpu_arch), + .addend = if (symbol.?.flags.import) 0 else @intCast(symbol.?.address(.{}, elf_file) - elf_file.tlsAddress()), }); }, } From b34310356725fb1b955b6bec11da235efdc96bab Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:43:23 +0100 Subject: [PATCH 10/17] elf+aarch64: handle gottp and .tls_common --- src/link/Elf/Atom.zig | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index fca2fbef27..61705dfcdb 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1628,6 +1628,12 @@ const aarch64 = struct { if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); }, + .TLSIE_ADR_GOTTPREL_PAGE21, + .TLSIE_LD64_GOTTPREL_LO12_NC, + => { + symbol.flags.needs_gottp = true; + }, + .TLSDESC_ADR_PAGE21, .TLSDESC_LD64_LO12, .TLSDESC_ADD_LO12, @@ -1769,6 +1775,23 @@ const aarch64 = struct { aarch64_util.writeAddImmInst(@bitCast(value), code); }, + .TLSIE_ADR_GOTTPREL_PAGE21 => { + const S_: i64 = @intCast(target.gotTpAddress(elf_file)); + const saddr: u64 = @intCast(P); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); + aarch64_util.writeAdrpInst(pages, code); + }, + + .TLSIE_LD64_GOTTPREL_LO12_NC => { + const S_: i64 = @intCast(target.gotTpAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); + aarch64_util.writeLoadStoreRegInst(offset, code); + }, + .TLSDESC_ADR_PAGE21 => { if (target.flags.has_tlsdesc) { const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); From 47100bd40a026710076d2d9be6e03937201e8adc Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:46:23 +0100 Subject: [PATCH 11/17] elf+aarch64: handle TLS GD model --- src/link/Elf/Atom.zig | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 61705dfcdb..63590402eb 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1634,9 +1634,16 @@ const aarch64 = struct { symbol.flags.needs_gottp = true; }, + .TLSGD_ADR_PAGE21, + .TLSGD_ADD_LO12_NC, + => { + symbol.flags.needs_tlsgd = true; + }, + .TLSDESC_ADR_PAGE21, .TLSDESC_LD64_LO12, .TLSDESC_ADD_LO12, + .TLSDESC_CALL, => { const should_relax = elf_file.base.isStatic() or (!is_dyn_lib and !symbol.flags.import); if (!should_relax) { @@ -1651,7 +1658,6 @@ const aarch64 = struct { .LDST32_ABS_LO12_NC, .LDST64_ABS_LO12_NC, .LDST128_ABS_LO12_NC, - .TLSDESC_CALL, => {}, else => try atom.reportUnhandledRelocError(rel, elf_file), @@ -1792,6 +1798,23 @@ const aarch64 = struct { aarch64_util.writeLoadStoreRegInst(offset, code); }, + .TLSGD_ADR_PAGE21 => { + const S_: i64 = @intCast(target.tlsGdAddress(elf_file)); + const saddr: u64 = @intCast(P); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); + aarch64_util.writeAdrpInst(pages, code); + }, + + .TLSGD_ADD_LO12_NC => { + const S_: i64 = @intCast(target.tlsGdAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = @truncate(taddr); + aarch64_util.writeAddImmInst(offset, code); + }, + .TLSDESC_ADR_PAGE21 => { if (target.flags.has_tlsdesc) { const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); From 7c5ddb6ae410a861e139ce36dec94434392bfdad Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 14:47:59 +0100 Subject: [PATCH 12/17] elf+aarch64: handle PREL32 reloc --- src/link/Elf/Atom.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 63590402eb..34c5602b0d 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1658,6 +1658,7 @@ const aarch64 = struct { .LDST32_ABS_LO12_NC, .LDST64_ABS_LO12_NC, .LDST128_ABS_LO12_NC, + .PREL32, => {}, else => try atom.reportUnhandledRelocError(rel, elf_file), @@ -1716,6 +1717,11 @@ const aarch64 = struct { aarch64_util.writeBranchImm(disp, code); }, + .PREL32 => { + const value = math.cast(i32, S + A - P) orelse return error.Overflow; + mem.writeInt(u32, code, @bitCast(value), .little); + }, + .ADR_PREL_PG_HI21 => { // TODO: check for relaxation of ADRP+ADD const saddr = @as(u64, @intCast(P)); From 859f9a22c4ac28a4e6b003b6e07c2c9912fcb074 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Fri, 8 Mar 2024 22:44:37 +0100 Subject: [PATCH 13/17] elf+aarch64: implement basic thunk support --- CMakeLists.txt | 1 + src/link/Elf.zig | 58 +++++++++- src/link/Elf/Atom.zig | 30 +++-- src/link/Elf/Symbol.zig | 2 +- src/link/Elf/thunks.zig | 243 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 319 insertions(+), 15 deletions(-) create mode 100644 src/link/Elf/thunks.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 38a10d6354..9a77b2a42c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -597,6 +597,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/src/link/Elf/relocatable.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/relocation.zig" "${CMAKE_SOURCE_DIR}/src/link/Elf/synthetic_sections.zig" + "${CMAKE_SOURCE_DIR}/src/link/Elf/thunks.zig" "${CMAKE_SOURCE_DIR}/src/link/MachO.zig" "${CMAKE_SOURCE_DIR}/src/link/MachO/Archive.zig" "${CMAKE_SOURCE_DIR}/src/link/MachO/Atom.zig" diff --git a/src/link/Elf.zig b/src/link/Elf.zig index b18e97a556..85ef62b4bc 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -206,6 +206,9 @@ num_ifunc_dynrelocs: usize = 0, /// List of atoms that are owned directly by the linker. atoms: std.ArrayListUnmanaged(Atom) = .{}, +/// List of range extension thunks. +thunks: std.ArrayListUnmanaged(Thunk) = .{}, + /// Table of last atom index in a section and matching atom free list if any. last_atom_and_free_list_table: LastAtomAndFreeListTable = .{}, @@ -255,7 +258,7 @@ pub fn createEmpty( }; const page_size: u32 = switch (target.cpu.arch) { - .powerpc64le => 0x10000, + .aarch64, .powerpc64le => 0x10000, .sparc64 => 0x2000, else => 0x1000, }; @@ -488,6 +491,7 @@ pub fn deinit(self: *Elf) void { self.start_stop_indexes.deinit(gpa); self.atoms.deinit(gpa); + self.thunks.deinit(gpa); for (self.last_atom_and_free_list_table.values()) |*value| { value.free_list.deinit(gpa); } @@ -3593,7 +3597,7 @@ fn sortInitFini(self: *Elf) !void { } }; - for (self.shdrs.items, 0..) |*shdr, shndx| { + for (self.shdrs.items, 0..) |shdr, shndx| { if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; var is_init_fini = false; @@ -4038,6 +4042,8 @@ fn updateSectionSizes(self: *Elf) !void { const target = self.base.comp.root_mod.resolved_target.result; for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { const shdr = &self.shdrs.items[shndx]; + if (atom_list.items.len == 0) continue; + if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; for (atom_list.items) |atom_index| { const atom_ptr = self.atom(atom_index) orelse continue; if (!atom_ptr.flags.alive) continue; @@ -4049,6 +4055,17 @@ fn updateSectionSizes(self: *Elf) !void { } } + if (self.requiresThunks()) { + for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { + const shdr = self.shdrs.items[shndx]; + if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; + if (atom_list.items.len == 0) continue; + + // Create jump/branch range extenders if needed. + try thunks.createThunks(shndx, self); + } + } + if (self.eh_frame_section_index) |index| { self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); } @@ -4576,6 +4593,13 @@ pub fn updateSymtabSize(self: *Elf) !void { nlocals += 1; } + for (self.thunks.items) |*th| { + th.output_symtab_ctx.ilocal = nlocals + 1; + th.calcSymtabSize(self); + nlocals += th.output_symtab_ctx.nlocals; + strsize += th.output_symtab_ctx.strsize; + } + for (files.items) |index| { const file_ptr = self.file(index).?; const ctx = switch (file_ptr) { @@ -4806,6 +4830,10 @@ pub fn writeSymtab(self: *Elf) !void { self.writeSectionSymbols(); + for (self.thunks.items) |th| { + th.writeSymtab(self); + } + if (self.zigObjectPtr()) |zig_object| { zig_object.asFile().writeSymtab(self); } @@ -5401,6 +5429,18 @@ pub fn addAtom(self: *Elf) !Atom.Index { return index; } +pub fn addThunk(self: *Elf) !Thunk.Index { + const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); + const th = try self.thunks.addOne(self.base.comp.gpa); + th.* = .{}; + return index; +} + +pub fn thunk(self: *Elf, index: Thunk.Index) *Thunk { + assert(index < self.thunks.items.len); + return &self.thunks.items[index]; +} + pub fn file(self: *Elf, index: File.Index) ?File { const tag = self.files.items(.tags)[index]; return switch (tag) { @@ -5957,6 +5997,10 @@ fn fmtDumpState( try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); } + try writer.writeAll("thunks\n"); + for (self.thunks.items, 0..) |th, index| { + try writer.print("thunk({d}) : {}\n", .{ index, th.fmt(self) }); + } try writer.print("{}\n", .{self.zig_got.fmt(self)}); try writer.print("{}\n", .{self.got.fmt(self)}); try writer.print("{}\n", .{self.plt.fmt(self)}); @@ -6024,6 +6068,14 @@ pub fn getTarget(self: Elf) std.Target { return self.base.comp.root_mod.resolved_target.result; } +fn requiresThunks(self: Elf) bool { + return switch (self.getTarget().cpu.arch) { + .aarch64 => true, + .x86_64, .riscv64 => false, + else => @panic("TODO unimplemented architecture"), + }; +} + /// The following three values are only observed at compile-time and used to emit a compile error /// to remind the programmer to update expected maximum numbers of different program header types /// so that we reserve enough space for the program header table up-front. @@ -6154,6 +6206,7 @@ const musl = @import("../musl.zig"); const relocatable = @import("Elf/relocatable.zig"); const relocation = @import("Elf/relocation.zig"); const target_util = @import("../target.zig"); +const thunks = @import("Elf/thunks.zig"); const trace = @import("../tracy.zig").trace; const synthetic_sections = @import("Elf/synthetic_sections.zig"); @@ -6186,6 +6239,7 @@ const PltGotSection = synthetic_sections.PltGotSection; const SharedObject = @import("Elf/SharedObject.zig"); const Symbol = @import("Elf/Symbol.zig"); const StringTable = @import("StringTable.zig"); +const Thunk = thunks.Thunk; const TypedValue = @import("../TypedValue.zig"); const VerneedSection = synthetic_sections.VerneedSection; const ZigGotSection = synthetic_sections.ZigGotSection; diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 34c5602b0d..4841501aa6 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -31,6 +31,9 @@ rel_num: u32 = 0, /// Index of this atom in the linker's atoms table. atom_index: Index = 0, +/// Index of the thunk for this atom. +thunk_index: Thunk.Index = 0, + /// Flags we use for state tracking. flags: Flags = .{}, @@ -64,6 +67,10 @@ pub fn file(self: Atom, elf_file: *Elf) ?File { return elf_file.file(self.file_index); } +pub fn thunk(self: Atom, elf_file: *Elf) *Thunk { + return elf_file.thunk(self.thunk_index); +} + pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr { return switch (self.file(elf_file).?) { .object => |x| x.shdrs.items[self.input_section_index], @@ -1681,6 +1688,7 @@ const aarch64 = struct { const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); const code = code_buffer[rel.r_offset..][0..4]; + const file_ptr = atom.file(elf_file).?; const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; _ = DTP; @@ -1701,18 +1709,15 @@ const aarch64 = struct { .CALL26, .JUMP26, => { - // TODO: add thunk support - const disp: i28 = math.cast(i28, S + A - P) orelse { - var err = try elf_file.addErrorWithNotes(1); - try err.addMsg(elf_file, "TODO: branch relocation target ({s}) exceeds max jump distance", .{ - target.name(elf_file), - }); - try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{ - atom.file(elf_file).?.fmtPath(), - atom.name(elf_file), - r_offset, - }); - return; + const disp: i28 = math.cast(i28, S + A - P) orelse blk: { + const th = atom.thunk(elf_file); + const target_index = switch (file_ptr) { + .zig_object => |x| x.symbol(rel.r_sym()), + .object => |x| x.symbols.items[rel.r_sym()], + else => unreachable, + }; + const S_: i64 = @intCast(th.targetAddress(target_index, elf_file)); + break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow; }; aarch64_util.writeBranchImm(disp, code); }, @@ -2173,3 +2178,4 @@ const Fde = eh_frame.Fde; const File = @import("file.zig").File; const Object = @import("Object.zig"); const Symbol = @import("Symbol.zig"); +const Thunk = @import("thunks.zig").Thunk; diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 59f19b74f9..0ddf19cd05 100644 --- a/src/link/Elf/Symbol.zig +++ b/src/link/Elf/Symbol.zig @@ -253,7 +253,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void { break :blk 0; } if (st_shndx == elf.SHN_ABS or st_shndx == elf.SHN_COMMON) break :blk symbol.address(.{ .plt = false }, elf_file); - const shdr = &elf_file.shdrs.items[st_shndx]; + const shdr = elf_file.shdrs.items[st_shndx]; if (shdr.sh_flags & elf.SHF_TLS != 0 and file_ptr != .linker_defined) break :blk symbol.address(.{ .plt = false }, elf_file) - elf_file.tlsAddress(); break :blk symbol.address(.{ .plt = false }, elf_file); diff --git a/src/link/Elf/thunks.zig b/src/link/Elf/thunks.zig new file mode 100644 index 0000000000..398a2acd93 --- /dev/null +++ b/src/link/Elf/thunks.zig @@ -0,0 +1,243 @@ +pub fn createThunks(shndx: u32, elf_file: *Elf) !void { + const gpa = elf_file.base.comp.gpa; + const cpu_arch = elf_file.getTarget().cpu.arch; + const shdr = &elf_file.shdrs.items[shndx]; + const atoms = elf_file.output_sections.get(shndx).?.items; + assert(atoms.len > 0); + + for (atoms) |atom_index| { + elf_file.atom(atom_index).?.value = @bitCast(@as(i64, -1)); + } + + var i: usize = 0; + while (i < atoms.len) { + const start = i; + const start_atom = elf_file.atom(atoms[start]).?; + assert(start_atom.flags.alive); + start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment); + i += 1; + + while (i < atoms.len and + shdr.sh_size - start_atom.value < maxAllowedDistance(cpu_arch)) : (i += 1) + { + const atom_index = atoms[i]; + const atom = elf_file.atom(atom_index).?; + assert(atom.flags.alive); + atom.value = try advance(shdr, atom.size, atom.alignment); + } + + // Insert a thunk at the group end + const thunk_index = try elf_file.addThunk(); + const thunk = elf_file.thunk(thunk_index); + thunk.output_section_index = shndx; + + // Scan relocs in the group and create trampolines for any unreachable callsite + for (atoms[start..i]) |atom_index| { + const atom = elf_file.atom(atom_index).?; + const file = atom.file(elf_file).?; + log.debug("atom({d}) {s}", .{ atom_index, atom.name(elf_file) }); + for (atom.relocs(elf_file)) |rel| { + const is_reachable = switch (cpu_arch) { + .aarch64 => aarch64.isReachable(atom, rel, elf_file), + .x86_64, .riscv64 => unreachable, + else => @panic("unsupported arch"), + }; + if (is_reachable) continue; + const target = switch (file) { + .zig_object => |x| x.symbol(rel.r_sym()), + .object => |x| x.symbols.items[rel.r_sym()], + else => unreachable, + }; + try thunk.symbols.put(gpa, target, {}); + } + atom.thunk_index = thunk_index; + } + + thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); + + log.debug("thunk({d}) : {}", .{ thunk_index, thunk.fmt(elf_file) }); + } +} + +fn advance(shdr: *elf.Elf64_Shdr, size: u64, alignment: Atom.Alignment) !u64 { + const offset = alignment.forward(shdr.sh_size); + const padding = offset - shdr.sh_size; + shdr.sh_size += padding + size; + shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits(1)); + return offset; +} + +/// A branch will need an extender if its target is larger than +/// `2^(jump_bits - 1) - margin` where margin is some arbitrary number. +fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 { + return switch (cpu_arch) { + .aarch64 => 0x500_000, + .x86_64, .riscv64 => unreachable, + else => @panic("unhandled arch"), + }; +} + +pub const Thunk = struct { + value: u64 = 0, + output_section_index: u32 = 0, + symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{}, + output_symtab_ctx: Elf.SymtabCtx = .{}, + + pub fn deinit(thunk: *Thunk, allocator: Allocator) void { + thunk.symbols.deinit(allocator); + } + + pub fn size(thunk: Thunk, elf_file: *Elf) usize { + const cpu_arch = elf_file.getTarget().cpu.arch; + return thunk.symbols.keys().len * trampolineSize(cpu_arch); + } + + pub fn address(thunk: Thunk, elf_file: *Elf) u64 { + const shdr = elf_file.shdrs.items[thunk.output_section_index]; + return shdr.sh_addr + thunk.value; + } + + pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) u64 { + const cpu_arch = elf_file.getTarget().cpu.arch; + return thunk.address(elf_file) + thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch); + } + + pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { + switch (elf_file.options.cpu_arch.?) { + .aarch64 => try aarch64.write(thunk, elf_file, writer), + .x86_64, .riscv64 => unreachable, + else => @panic("unhandled arch"), + } + } + + pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void { + thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); + for (thunk.symbols.keys()) |sym_index| { + const sym = elf_file.symbol(sym_index); + thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1)); + } + } + + pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void { + const cpu_arch = elf_file.getTarget().cpu.arch; + for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |sym_index, ilocal| { + const sym = elf_file.symbol(sym_index); + const st_name = @as(u32, @intCast(elf_file.strtab.items.len)); + elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file)); + elf_file.strtab.appendSliceAssumeCapacity("$thunk"); + elf_file.strtab.appendAssumeCapacity(0); + elf_file.symtab.items[ilocal] = .{ + .st_name = st_name, + .st_info = elf.STT_FUNC, + .st_other = 0, + .st_shndx = @intCast(thunk.output_section_index), + .st_value = thunk.targetAddress(sym_index, elf_file), + .st_size = trampolineSize(cpu_arch), + }; + } + } + + fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) usize { + return switch (cpu_arch) { + .aarch64 => aarch64.trampoline_size, + .x86_64, .riscv64 => unreachable, + else => @panic("unhandled arch"), + }; + } + + pub fn format( + thunk: Thunk, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = thunk; + _ = unused_fmt_string; + _ = options; + _ = writer; + @compileError("do not format Thunk directly"); + } + + pub fn fmt(thunk: Thunk, elf_file: *Elf) std.fmt.Formatter(format2) { + return .{ .data = .{ + .thunk = thunk, + .elf_file = elf_file, + } }; + } + + const FormatContext = struct { + thunk: Thunk, + elf_file: *Elf, + }; + + fn format2( + ctx: FormatContext, + comptime unused_fmt_string: []const u8, + options: std.fmt.FormatOptions, + writer: anytype, + ) !void { + _ = options; + _ = unused_fmt_string; + const thunk = ctx.thunk; + const elf_file = ctx.elf_file; + try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) }); + for (thunk.symbols.keys()) |index| { + const sym = elf_file.symbol(index); + try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.name(elf_file), sym.value }); + } + } + + pub const Index = u32; +}; + +const aarch64 = struct { + fn isReachable(atom: *const Atom, rel: elf.Elf64_Rela, elf_file: *Elf) bool { + const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); + if (r_type != .CALL26 and r_type != .JUMP26) return true; + const file = atom.file(elf_file).?; + const target_index = switch (file) { + .zig_object => |x| x.symbol(rel.r_sym()), + .object => |x| x.symbols.items[rel.r_sym()], + else => unreachable, + }; + const target = elf_file.symbol(target_index); + if (target.flags.has_plt) return false; + if (atom.output_section_index != target.output_section_index) return false; + const target_atom = target.atom(elf_file).?; + if (target_atom.value == @as(u64, @bitCast(@as(i64, -1)))) return false; + const saddr = @as(i64, @intCast(atom.address(elf_file) + rel.r_offset)); + const taddr: i64 = @intCast(target.address(.{}, elf_file)); + _ = math.cast(i28, taddr + rel.r_addend - saddr) orelse return false; + return true; + } + + fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { + for (thunk.symbols.keys(), 0..) |sym_index, i| { + const sym = elf_file.symbol(sym_index); + const saddr = thunk.address(elf_file) + 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(taddr); + try writer.writeInt(u32, Instruction.add(.x16, .x16, off, false).toU32(), .little); + try writer.writeInt(u32, Instruction.br(.x16).toU32(), .little); + } + } + + const trampoline_size = 3 * @sizeOf(u32); + + const util = @import("../aarch64.zig"); + const Instruction = util.Instruction; +}; + +const assert = std.debug.assert; +const elf = std.elf; +const log = std.log.scoped(.link); +const math = std.math; +const mem = std.mem; +const std = @import("std"); + +const Allocator = mem.Allocator; +const Atom = @import("Atom.zig"); +const Elf = @import("../Elf.zig"); +const Symbol = @import("Symbol.zig"); From 229468b7a9a47c08a90684419a5c210ff2af2b4a Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 9 Mar 2024 18:55:52 +0100 Subject: [PATCH 14/17] elf+aarch64: fix 32bit build --- src/link/Elf/Atom.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 4841501aa6..eb78f10068 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1687,7 +1687,7 @@ const aarch64 = struct { const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); - const code = code_buffer[rel.r_offset..][0..4]; + const code = code_buffer[r_offset..][0..4]; const file_ptr = atom.file(elf_file).?; const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; From b7b63855d04c8a757b9c33982cccf538676256ad Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 9 Mar 2024 19:20:59 +0100 Subject: [PATCH 15/17] test/link/elf: enable tests for aarch64 cpu arch --- test/link/elf.zig | 238 +++++++++++++++++++++++++--------------------- 1 file changed, 129 insertions(+), 109 deletions(-) diff --git a/test/link/elf.zig b/test/link/elf.zig index 97b67f6cdf..9c08677429 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -20,30 +20,142 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { .os_tag = .linux, .abi = .gnu, }); - const aarch64_musl = b.resolveTargetQuery(.{ - .cpu_arch = .aarch64, - .os_tag = .linux, - .abi = .musl, - }); + // const aarch64_musl = b.resolveTargetQuery(.{ + // .cpu_arch = .aarch64, + // .os_tag = .linux, + // .abi = .musl, + // }); + // const aarch64_gnu = b.resolveTargetQuery(.{ + // .cpu_arch = .aarch64, + // .os_tag = .linux, + // .abi = .gnu, + // }); const riscv64_musl = b.resolveTargetQuery(.{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .musl, }); - // x86_64 tests - // Exercise linker in -r mode + // Common tests + for (&[_]std.Target.Cpu.Arch{ + .x86_64, + .aarch64, + }) |cpu_arch| { + const musl_target = b.resolveTargetQuery(.{ + .cpu_arch = cpu_arch, + .os_tag = .linux, + .abi = .musl, + }); + const gnu_target = b.resolveTargetQuery(.{ + .cpu_arch = cpu_arch, + .os_tag = .linux, + .abi = .gnu, + }); + + // Exercise linker in -r mode + elf_step.dependOn(testEmitRelocatable(b, .{ .target = musl_target })); + elf_step.dependOn(testRelocatableArchive(b, .{ .target = musl_target })); + elf_step.dependOn(testRelocatableEhFrame(b, .{ .target = musl_target })); + elf_step.dependOn(testRelocatableNoEhFrame(b, .{ .target = musl_target })); + + // Exercise linker in ar mode + elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target })); + + // Exercise linker with LLVM backend + // musl tests + elf_step.dependOn(testAbsSymbols(b, .{ .target = musl_target })); + elf_step.dependOn(testCommonSymbols(b, .{ .target = musl_target })); + elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = musl_target })); + elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target })); + elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target })); + elf_step.dependOn(testGcSections(b, .{ .target = musl_target })); + elf_step.dependOn(testImageBase(b, .{ .target = musl_target })); + elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target })); + elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target })); + // https://github.com/ziglang/zig/issues/17449 + // elf_step.dependOn(testLargeBss(b, .{ .target = musl_target })); + elf_step.dependOn(testLinkingC(b, .{ .target = musl_target })); + elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target })); + elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target })); + // https://github.com/ziglang/zig/issues/17451 + // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = musl_target })); + elf_step.dependOn(testTlsStatic(b, .{ .target = musl_target })); + elf_step.dependOn(testStrip(b, .{ .target = musl_target })); + + // glibc tests + elf_step.dependOn(testAsNeeded(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 + // elf_step.dependOn(testCanonicalPlt(b, .{ .target = gnu_target })); + elf_step.dependOn(testCopyrel(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 + // elf_step.dependOn(testCopyrelAlias(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 + // elf_step.dependOn(testCopyrelAlignment(b, .{ .target = gnu_target })); + elf_step.dependOn(testDsoPlt(b, .{ .target = gnu_target })); + elf_step.dependOn(testDsoUndef(b, .{ .target = gnu_target })); + elf_step.dependOn(testExportDynamic(b, .{ .target = gnu_target })); + elf_step.dependOn(testExportSymbolsFromExe(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 + // elf_step.dependOn(testFuncAddress(b, .{ .target = gnu_target })); + elf_step.dependOn(testHiddenWeakUndef(b, .{ .target = gnu_target })); + elf_step.dependOn(testIFuncAlias(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 + // elf_step.dependOn(testIFuncDlopen(b, .{ .target = gnu_target })); + elf_step.dependOn(testIFuncDso(b, .{ .target = gnu_target })); + elf_step.dependOn(testIFuncDynamic(b, .{ .target = gnu_target })); + elf_step.dependOn(testIFuncExport(b, .{ .target = gnu_target })); + elf_step.dependOn(testIFuncFuncPtr(b, .{ .target = gnu_target })); + elf_step.dependOn(testIFuncNoPlt(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 ?? + // elf_step.dependOn(testIFuncStatic(b, .{ .target = gnu_target })); + // elf_step.dependOn(testIFuncStaticPie(b, .{ .target = gnu_target })); + elf_step.dependOn(testInitArrayOrder(b, .{ .target = gnu_target })); + elf_step.dependOn(testLargeAlignmentDso(b, .{ .target = gnu_target })); + elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = gnu_target })); + elf_step.dependOn(testLargeBss(b, .{ .target = gnu_target })); + elf_step.dependOn(testLinkOrder(b, .{ .target = gnu_target })); + elf_step.dependOn(testLdScript(b, .{ .target = gnu_target })); + elf_step.dependOn(testLdScriptPathError(b, .{ .target = gnu_target })); + elf_step.dependOn(testLdScriptAllowUndefinedVersion(b, .{ .target = gnu_target, .use_lld = true })); + elf_step.dependOn(testLdScriptDisallowUndefinedVersion(b, .{ .target = gnu_target, .use_lld = true })); + // https://github.com/ziglang/zig/issues/17451 + // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = gnu_target })); + elf_step.dependOn(testPie(b, .{ .target = gnu_target })); + elf_step.dependOn(testPltGot(b, .{ .target = gnu_target })); + elf_step.dependOn(testPreinitArray(b, .{ .target = gnu_target })); + elf_step.dependOn(testSharedAbsSymbol(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsDfStaticTls(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsDso(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsGd(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsGdNoPlt(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsGdToIe(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsIe(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsLargeAlignment(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsLargeTbss(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsLargeStaticImage(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsLd(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsLdDso(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsLdNoPlt(b, .{ .target = gnu_target })); + // https://github.com/ziglang/zig/issues/17430 + // elf_step.dependOn(testTlsNoPic(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsOffsetAlignment(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsPic(b, .{ .target = gnu_target })); + elf_step.dependOn(testTlsSmallAlignment(b, .{ .target = gnu_target })); + elf_step.dependOn(testUnknownFileTypeError(b, .{ .target = gnu_target })); + elf_step.dependOn(testUnresolvedError(b, .{ .target = gnu_target })); + elf_step.dependOn(testWeakExports(b, .{ .target = gnu_target })); + elf_step.dependOn(testWeakUndefsDso(b, .{ .target = gnu_target })); + elf_step.dependOn(testZNow(b, .{ .target = gnu_target })); + elf_step.dependOn(testZStackSize(b, .{ .target = gnu_target })); + } + + // x86_64 specific tests + elf_step.dependOn(testMismatchedCpuArchitectureError(b, .{ .target = x86_64_musl })); + elf_step.dependOn(testZText(b, .{ .target = x86_64_gnu })); + + // x86_64 self-hosted backend elf_step.dependOn(testEmitRelocatable(b, .{ .use_llvm = false, .target = x86_64_musl })); - elf_step.dependOn(testEmitRelocatable(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testRelocatableArchive(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testRelocatableEhFrame(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testRelocatableNoEhFrame(b, .{ .target = x86_64_musl })); - - // Exercise linker in ar mode - elf_step.dependOn(testEmitStaticLib(b, .{ .target = x86_64_musl })); elf_step.dependOn(testEmitStaticLibZig(b, .{ .use_llvm = false, .target = x86_64_musl })); - - // Exercise linker with self-hosted backend (no LLVM) elf_step.dependOn(testGcSectionsZig(b, .{ .use_llvm = false, .target = default_target })); elf_step.dependOn(testLinkingObj(b, .{ .use_llvm = false, .target = default_target })); elf_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = default_target })); @@ -51,99 +163,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { elf_step.dependOn(testImportingDataDynamic(b, .{ .use_llvm = false, .target = x86_64_gnu })); elf_step.dependOn(testImportingDataStatic(b, .{ .use_llvm = false, .target = x86_64_musl })); - // Exercise linker with LLVM backend - // musl tests - elf_step.dependOn(testAbsSymbols(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testCommonSymbols(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testCommonSymbolsInArchive(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testEmptyObject(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testEntryPoint(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testGcSections(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testImageBase(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testInitArrayOrder(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = x86_64_musl })); - // https://github.com/ziglang/zig/issues/17449 - // elf_step.dependOn(testLargeBss(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testLinkingC(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testLinkingCpp(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testLinkingZig(b, .{ .target = x86_64_musl })); - // https://github.com/ziglang/zig/issues/17451 - // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testTlsStatic(b, .{ .target = x86_64_musl })); - elf_step.dependOn(testStrip(b, .{ .target = x86_64_musl })); - - // glibc tests - elf_step.dependOn(testAsNeeded(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 - // elf_step.dependOn(testCanonicalPlt(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testCopyrel(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 - // elf_step.dependOn(testCopyrelAlias(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 - // elf_step.dependOn(testCopyrelAlignment(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testDsoPlt(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testDsoUndef(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testExportDynamic(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testExportSymbolsFromExe(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 - // elf_step.dependOn(testFuncAddress(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testHiddenWeakUndef(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testIFuncAlias(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 - // elf_step.dependOn(testIFuncDlopen(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testIFuncDso(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testIFuncDynamic(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testIFuncExport(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testIFuncFuncPtr(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testIFuncNoPlt(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 ?? - // elf_step.dependOn(testIFuncStatic(b, .{ .target = x86_64_gnu })); - // elf_step.dependOn(testIFuncStaticPie(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testInitArrayOrder(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLargeAlignmentDso(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLargeBss(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLinkOrder(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLdScript(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLdScriptPathError(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testLdScriptAllowUndefinedVersion(b, .{ .target = x86_64_gnu, .use_lld = true })); - elf_step.dependOn(testLdScriptDisallowUndefinedVersion(b, .{ .target = x86_64_gnu, .use_lld = true })); - elf_step.dependOn(testMismatchedCpuArchitectureError(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17451 - // elf_step.dependOn(testNoEhFrameHdr(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testPie(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testPltGot(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testPreinitArray(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testSharedAbsSymbol(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsDfStaticTls(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsDso(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsGd(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsGdNoPlt(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsGdToIe(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsIe(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsLargeAlignment(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsLargeTbss(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsLargeStaticImage(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsLd(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsLdDso(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsLdNoPlt(b, .{ .target = x86_64_gnu })); - // https://github.com/ziglang/zig/issues/17430 - // elf_step.dependOn(testTlsNoPic(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsOffsetAlignment(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsPic(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testTlsSmallAlignment(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testUnknownFileTypeError(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testUnresolvedError(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testWeakExports(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testWeakUndefsDso(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testZNow(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testZStackSize(b, .{ .target = x86_64_gnu })); - elf_step.dependOn(testZText(b, .{ .target = x86_64_gnu })); - - // aarch64 tests - elf_step.dependOn(testLinkingC(b, .{ .target = aarch64_musl })); - - // riscv64 tests + // riscv64 linker backend is currently not complete enough to support more elf_step.dependOn(testLinkingC(b, .{ .target = riscv64_musl })); return elf_step; From 2cdbad6f10ec5a3d07de3d02a2f0cb9e9660bd58 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 9 Mar 2024 19:34:34 +0100 Subject: [PATCH 16/17] elf+aarch64: handle PREL64 reloc --- src/link/Elf/Atom.zig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index eb78f10068..f391326670 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1666,6 +1666,7 @@ const aarch64 = struct { .LDST64_ABS_LO12_NC, .LDST128_ABS_LO12_NC, .PREL32, + .PREL64, => {}, else => try atom.reportUnhandledRelocError(rel, elf_file), @@ -1727,6 +1728,11 @@ const aarch64 = struct { mem.writeInt(u32, code, @bitCast(value), .little); }, + .PREL64 => { + const value = S + A - P; + mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little); + }, + .ADR_PREL_PG_HI21 => { // TODO: check for relaxation of ADRP+ADD const saddr = @as(u64, @intCast(P)); From 1a6b2e84ac5d88f00bfb281c8101f2b69a962b67 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 10 Mar 2024 10:39:31 +0100 Subject: [PATCH 17/17] test/link/elf: remove pie hack due to QEMU bug that is now fixed --- test/link/elf.zig | 78 ----------------------------------------------- 1 file changed, 78 deletions(-) diff --git a/test/link/elf.zig b/test/link/elf.zig index 9c08677429..20cc95c92a 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -259,8 +259,6 @@ fn testAsNeeded(b: *Build, opts: Options) *Step { exe.addLibraryPath(libbaz.getEmittedBinDirectory()); exe.addRPath(libbaz.getEmittedBinDirectory()); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("42\n"); @@ -289,8 +287,6 @@ fn testAsNeeded(b: *Build, opts: Options) *Step { exe.addLibraryPath(libbaz.getEmittedBinDirectory()); exe.addRPath(libbaz.getEmittedBinDirectory()); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("42\n"); @@ -509,8 +505,6 @@ fn testCopyrel(b: *Build, opts: Options) *Step { }); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3 5\n"); @@ -676,8 +670,6 @@ fn testDsoPlt(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("Hello WORLD\n"); @@ -715,8 +707,6 @@ fn testDsoUndef(b: *Build, opts: Options) *Step { \\} , &.{}); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectExitCode(0); @@ -1300,8 +1290,6 @@ fn testIFuncAlias(b: *Build, opts: Options) *Step { , &.{}); exe.root_module.pic = true; exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectExitCode(0); @@ -1416,8 +1404,6 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step { addCSourceBytes(exe, main_c, &.{}); exe.linkLibC(); exe.link_z_lazy = true; - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("Hello world\n"); @@ -1427,8 +1413,6 @@ fn testIFuncDynamic(b: *Build, opts: Options) *Step { const exe = addExecutable(b, opts, .{ .name = "other" }); addCSourceBytes(exe, main_c, &.{}); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("Hello world\n"); @@ -1492,8 +1476,6 @@ fn testIFuncFuncPtr(b: *Build, opts: Options) *Step { , &.{}); exe.root_module.pic = true; exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3\n"); @@ -1523,8 +1505,6 @@ fn testIFuncNoPlt(b: *Build, opts: Options) *Step { , &.{"-fno-plt"}); exe.root_module.pic = true; exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("Hello world\n"); @@ -1854,8 +1834,6 @@ fn testLargeAlignmentDso(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("Hello world"); @@ -1890,8 +1868,6 @@ fn testLargeAlignmentExe(b: *Build, opts: Options) *Step { , &.{}); exe.link_function_sections = true; exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const check = exe.checkObject(); check.checkInSymtab(); @@ -1920,8 +1896,6 @@ fn testLargeBss(b: *Build, opts: Options) *Step { \\} , &.{}); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectExitCode(0); @@ -2015,8 +1989,6 @@ fn testLdScript(b: *Build, opts: Options) *Step { exe.addLibraryPath(dso.getEmittedBinDirectory()); exe.addRPath(dso.getEmittedBinDirectory()); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectExitCode(0); @@ -2368,8 +2340,6 @@ fn testPltGot(b: *Build, opts: Options) *Step { exe.linkLibrary(dso); exe.root_module.pic = true; exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("Hello world\n"); @@ -2772,8 +2742,6 @@ fn testTlsDso(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("5 3 5 3 5 3\n"); @@ -2932,8 +2900,6 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { exe.linkLibrary(a_so); exe.linkLibrary(b_so); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("1 2 3 4 5 6\n"); @@ -2947,8 +2913,6 @@ fn testTlsGdNoPlt(b: *Build, opts: Options) *Step { exe.linkLibrary(b_so); exe.linkLibC(); // exe.link_relax = false; // TODO - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("1 2 3 4 5 6\n"); @@ -2996,8 +2960,6 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { exe.addObject(b_o); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("1 2 3\n"); @@ -3013,8 +2975,6 @@ fn testTlsGdToIe(b: *Build, opts: Options) *Step { exe.addObject(b_o); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("1 2 3\n"); @@ -3096,8 +3056,6 @@ fn testTlsIe(b: *Build, opts: Options) *Step { exe.addObject(main_o); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual(exp_stdout); @@ -3110,8 +3068,6 @@ fn testTlsIe(b: *Build, opts: Options) *Step { exe.linkLibrary(dso); exe.linkLibC(); // exe.link_relax = false; // TODO - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual(exp_stdout); @@ -3167,8 +3123,6 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step { exe.addObject(c_o); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("42 1 2 3\n"); @@ -3181,8 +3135,6 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step { exe.addObject(b_o); exe.addObject(c_o); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("42 1 2 3\n"); @@ -3216,8 +3168,6 @@ fn testTlsLargeTbss(b: *Build, opts: Options) *Step { \\} , &.{}); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3 0 5 0 0 0\n"); @@ -3240,8 +3190,6 @@ fn testTlsLargeStaticImage(b: *Build, opts: Options) *Step { , &.{}); exe.root_module.pic = true; exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("1 2 3 0 5\n"); @@ -3286,8 +3234,6 @@ fn testTlsLd(b: *Build, opts: Options) *Step { exe.addObject(main_o); exe.addObject(a_o); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual(exp_stdout); @@ -3300,8 +3246,6 @@ fn testTlsLd(b: *Build, opts: Options) *Step { exe.addObject(a_o); exe.linkLibC(); // exe.link_relax = false; // TODO - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual(exp_stdout); @@ -3335,8 +3279,6 @@ fn testTlsLdDso(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("1 2\n"); @@ -3380,8 +3322,6 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step { exe.addObject(a_o); exe.addObject(b_o); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3 5 3 5\n"); @@ -3394,8 +3334,6 @@ fn testTlsLdNoPlt(b: *Build, opts: Options) *Step { exe.addObject(b_o); exe.linkLibC(); // exe.link_relax = false; // TODO - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3 5 3 5\n"); @@ -3481,8 +3419,6 @@ fn testTlsOffsetAlignment(b: *Build, opts: Options) *Step { exe.addRPath(dso.getEmittedBinDirectory()); exe.linkLibC(); exe.root_module.pic = true; - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectExitCode(0); @@ -3519,8 +3455,6 @@ fn testTlsPic(b: *Build, opts: Options) *Step { , &.{}); exe.addObject(obj); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3 5 3 5\n"); @@ -3568,8 +3502,6 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step { exe.addObject(b_o); exe.addObject(c_o); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("42\n"); @@ -3585,8 +3517,6 @@ fn testTlsSmallAlignment(b: *Build, opts: Options) *Step { exe.addObject(c_o); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("42\n"); @@ -3737,8 +3667,6 @@ fn testWeakExports(b: *Build, opts: Options) *Step { const exe = addExecutable(b, opts, .{ .name = "main" }); exe.addObject(obj); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const check = exe.checkObject(); check.checkInDynamicSymtab(); @@ -3771,8 +3699,6 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("bar=-1\n"); @@ -3789,8 +3715,6 @@ fn testWeakUndefsDso(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("bar=5\n"); @@ -3905,8 +3829,6 @@ fn testZText(b: *Build, opts: Options) *Step { , &.{}); exe.linkLibrary(dso); exe.linkLibC(); - // https://github.com/ziglang/zig/issues/17619 - exe.pie = true; const run = addRunArtifact(exe); run.expectStdOutEqual("3\n");