aboutsummaryrefslogtreecommitdiff
path: root/src/link/Elf.zig
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2024-03-08 22:44:37 +0100
committerJakub Konka <kubkon@jakubkonka.com>2024-03-08 22:46:18 +0100
commit859f9a22c4ac28a4e6b003b6e07c2c9912fcb074 (patch)
tree1020151bec8fb6c54eb15334d7095a8b4b16605b /src/link/Elf.zig
parent7c5ddb6ae410a861e139ce36dec94434392bfdad (diff)
downloadzig-859f9a22c4ac28a4e6b003b6e07c2c9912fcb074.tar.gz
zig-859f9a22c4ac28a4e6b003b6e07c2c9912fcb074.zip
elf+aarch64: implement basic thunk support
Diffstat (limited to 'src/link/Elf.zig')
-rw-r--r--src/link/Elf.zig58
1 files changed, 56 insertions, 2 deletions
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;