diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-03-08 22:44:37 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-03-08 22:46:18 +0100 |
| commit | 859f9a22c4ac28a4e6b003b6e07c2c9912fcb074 (patch) | |
| tree | 1020151bec8fb6c54eb15334d7095a8b4b16605b /src/link/Elf.zig | |
| parent | 7c5ddb6ae410a861e139ce36dec94434392bfdad (diff) | |
| download | zig-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.zig | 58 |
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; |
