mirror of
https://github.com/ziglang/zig.git
synced 2024-11-29 07:40:14 +00:00
Merge pull request #19225 from ziglang/elf-aarch64
elf: port aarch64 support from zld
This commit is contained in:
commit
c1bda06c14
@ -598,6 +598,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"
|
||||
|
116
src/link/Elf.zig
116
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);
|
||||
}
|
||||
@ -1373,7 +1377,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", .{});
|
||||
@ -2098,7 +2109,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);
|
||||
}
|
||||
}
|
||||
@ -3164,11 +3174,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_
|
||||
@ -3578,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;
|
||||
@ -4023,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;
|
||||
@ -4034,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);
|
||||
}
|
||||
@ -4047,7 +4079,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| {
|
||||
@ -4055,7 +4087,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| {
|
||||
@ -4490,7 +4522,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;
|
||||
@ -4561,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) {
|
||||
@ -4692,14 +4731,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 +4763,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);
|
||||
@ -4747,7 +4779,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);
|
||||
@ -4798,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);
|
||||
}
|
||||
@ -5393,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) {
|
||||
@ -5572,11 +5620,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 {
|
||||
@ -5943,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)});
|
||||
@ -6010,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.
|
||||
@ -6140,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");
|
||||
|
||||
@ -6172,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;
|
||||
|
@ -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],
|
||||
@ -1592,6 +1599,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);
|
||||
@ -1620,6 +1629,35 @@ const aarch64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
.TLSLE_ADD_TPREL_HI12,
|
||||
.TLSLE_ADD_TPREL_LO12_NC,
|
||||
=> {
|
||||
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;
|
||||
},
|
||||
|
||||
.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) {
|
||||
symbol.flags.needs_tlsdesc = true;
|
||||
}
|
||||
},
|
||||
|
||||
.ADD_ABS_LO12_NC,
|
||||
.ADR_PREL_LO21,
|
||||
.LDST8_ABS_LO12_NC,
|
||||
@ -1627,6 +1665,8 @@ const aarch64 = struct {
|
||||
.LDST32_ABS_LO12_NC,
|
||||
.LDST64_ABS_LO12_NC,
|
||||
.LDST128_ABS_LO12_NC,
|
||||
.PREL32,
|
||||
.PREL64,
|
||||
=> {},
|
||||
|
||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||
@ -1640,7 +1680,7 @@ const aarch64 = struct {
|
||||
target: *const Symbol,
|
||||
args: ResolveArgs,
|
||||
it: *RelocsIterator,
|
||||
code: []u8,
|
||||
code_buffer: []u8,
|
||||
stream: anytype,
|
||||
) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void {
|
||||
_ = it;
|
||||
@ -1648,9 +1688,10 @@ 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[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;
|
||||
_ = TP;
|
||||
_ = DTP;
|
||||
_ = ZIG_GOT;
|
||||
|
||||
@ -1669,20 +1710,27 @@ 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;
|
||||
};
|
||||
try aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]);
|
||||
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);
|
||||
},
|
||||
|
||||
.PREL64 => {
|
||||
const value = S + A - P;
|
||||
mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
|
||||
},
|
||||
|
||||
.ADR_PREL_PG_HI21 => {
|
||||
@ -1690,14 +1738,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);
|
||||
},
|
||||
|
||||
.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);
|
||||
} else {
|
||||
// TODO: relax
|
||||
var err = try elf_file.addErrorWithNotes(1);
|
||||
@ -1712,10 +1760,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);
|
||||
},
|
||||
|
||||
.ADD_ABS_LO12_NC => {
|
||||
const taddr = @as(u64, @intCast(S + A));
|
||||
aarch64_util.writeAddImmInst(@truncate(taddr), code);
|
||||
},
|
||||
|
||||
.ADD_ABS_LO12_NC,
|
||||
.LDST8_ABS_LO12_NC,
|
||||
.LDST16_ABS_LO12_NC,
|
||||
.LDST32_ABS_LO12_NC,
|
||||
@ -1724,16 +1776,121 @@ 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);
|
||||
},
|
||||
|
||||
.TLSLE_ADD_TPREL_HI12 => {
|
||||
const value = math.cast(i12, (S + A - TP) >> 12) orelse
|
||||
return error.Overflow;
|
||||
aarch64_util.writeAddImmInst(@bitCast(value), code);
|
||||
},
|
||||
|
||||
.TLSLE_ADD_TPREL_LO12_NC => {
|
||||
const value: i12 = @truncate(S + A - TP);
|
||||
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);
|
||||
},
|
||||
|
||||
.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));
|
||||
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 => {
|
||||
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 => {
|
||||
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) {
|
||||
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),
|
||||
@ -1768,6 +1925,8 @@ const aarch64 = struct {
|
||||
}
|
||||
|
||||
const aarch64_util = @import("../aarch64.zig");
|
||||
const Instruction = aarch64_util.Instruction;
|
||||
const Register = aarch64_util.Register;
|
||||
};
|
||||
|
||||
const riscv = struct {
|
||||
@ -2025,3 +2184,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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -139,14 +139,16 @@ 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 {
|
||||
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 {
|
||||
@ -251,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);
|
||||
@ -441,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;
|
||||
|
@ -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);
|
||||
|
@ -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()),
|
||||
});
|
||||
},
|
||||
}
|
||||
@ -857,8 +867,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 +885,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 +948,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 +961,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 +995,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 math.divExact(u12, @truncate(got_plt_addr + 16), 8);
|
||||
const add_off: u12 = @truncate(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 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)),
|
||||
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 {
|
||||
@ -1046,23 +1140,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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1091,6 +1186,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 math.divExact(u12, @truncate(target_addr), 8);
|
||||
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 {
|
||||
@ -1629,6 +1768,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");
|
||||
|
243
src/link/Elf/thunks.zig
Normal file
243
src/link/Elf/thunks.zig
Normal file
@ -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");
|
@ -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,
|
||||
|
@ -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(),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
@ -239,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");
|
||||
@ -269,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");
|
||||
@ -489,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");
|
||||
@ -656,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");
|
||||
@ -695,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);
|
||||
@ -1280,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);
|
||||
@ -1396,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");
|
||||
@ -1407,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");
|
||||
@ -1472,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");
|
||||
@ -1503,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");
|
||||
@ -1834,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");
|
||||
@ -1870,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();
|
||||
@ -1900,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);
|
||||
@ -1995,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);
|
||||
@ -2348,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");
|
||||
@ -2752,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");
|
||||
@ -2912,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");
|
||||
@ -2927,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");
|
||||
@ -2976,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");
|
||||
@ -2993,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");
|
||||
@ -3076,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);
|
||||
@ -3090,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);
|
||||
@ -3147,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");
|
||||
@ -3161,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");
|
||||
@ -3196,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");
|
||||
@ -3220,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");
|
||||
@ -3266,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);
|
||||
@ -3280,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);
|
||||
@ -3315,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");
|
||||
@ -3360,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");
|
||||
@ -3374,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");
|
||||
@ -3461,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);
|
||||
@ -3499,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");
|
||||
@ -3548,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");
|
||||
@ -3565,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");
|
||||
@ -3717,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();
|
||||
@ -3751,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");
|
||||
@ -3769,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");
|
||||
@ -3885,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");
|
||||
|
Loading…
Reference in New Issue
Block a user