authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 13:44:06+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-09-04 13:44:06+02:00
logb6caab63cb85d195230f939c4fc408b680866e22
tree1f56ea87ca2c7be70f96e416c4b940d349322910
parentf3d527c0822bd24bcd01fbcf3d670a7633a92468

elf: actually commit AtomList.zig


1 files changed, 206 insertions(+), 0 deletions(-)

src/link/Elf/AtomList.zig created+206
...@@ -0,0 +1,206 @@
1value: i64 = 0,
2size: u64 = 0,
3alignment: Atom.Alignment = .@"1",
4output_section_index: u32 = 0,
5atoms: std.ArrayListUnmanaged(Elf.Ref) = .{},
6
7pub fn deinit(list: *AtomList, allocator: Allocator) void {
8 list.atoms.deinit(allocator);
9}
10
11pub fn address(list: AtomList, elf_file: *Elf) i64 {
12 const shdr = elf_file.sections.items(.shdr)[list.output_section_index];
13 return @as(i64, @intCast(shdr.sh_addr)) + list.value;
14}
15
16pub fn offset(list: AtomList, elf_file: *Elf) u64 {
17 const shdr = elf_file.sections.items(.shdr)[list.output_section_index];
18 return shdr.sh_offset + @as(u64, @intCast(list.value));
19}
20
21pub fn updateSize(list: *AtomList, elf_file: *Elf) void {
22 for (list.atoms.items) |ref| {
23 const atom_ptr = elf_file.atom(ref).?;
24 assert(atom_ptr.alive);
25 const off = atom_ptr.alignment.forward(list.size);
26 const padding = off - list.size;
27 atom_ptr.value = @intCast(off);
28 list.size += padding + atom_ptr.size;
29 list.alignment = list.alignment.max(atom_ptr.alignment);
30 }
31}
32
33pub fn allocate(list: *AtomList, elf_file: *Elf) !void {
34 const alloc_res = try elf_file.allocateChunk(.{
35 .shndx = list.output_section_index,
36 .size = list.size,
37 .alignment = list.alignment,
38 .requires_padding = false,
39 });
40 list.value = @intCast(alloc_res.value);
41
42 const slice = elf_file.sections.slice();
43 const shdr = &slice.items(.shdr)[list.output_section_index];
44 const last_atom_ref = &slice.items(.last_atom)[list.output_section_index];
45
46 const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom|
47 placement_atom.nextAtom(elf_file) == null
48 else
49 true;
50 if (expand_section) last_atom_ref.* = list.lastAtom(elf_file).ref();
51 shdr.sh_addralign = @max(shdr.sh_addralign, list.alignment.toByteUnits().?);
52
53 // FIXME:JK this currently ignores Thunks as valid chunks.
54 {
55 var idx: usize = 0;
56 while (idx < list.atoms.items.len) : (idx += 1) {
57 const curr_atom_ptr = elf_file.atom(list.atoms.items[idx]).?;
58 if (idx > 0) {
59 curr_atom_ptr.prev_atom_ref = list.atoms.items[idx - 1];
60 }
61 if (idx + 1 < list.atoms.items.len) {
62 curr_atom_ptr.next_atom_ref = list.atoms.items[idx + 1];
63 }
64 }
65 }
66
67 if (elf_file.atom(alloc_res.placement)) |placement_atom| {
68 list.firstAtom(elf_file).prev_atom_ref = placement_atom.ref();
69 list.lastAtom(elf_file).next_atom_ref = placement_atom.next_atom_ref;
70 placement_atom.next_atom_ref = list.firstAtom(elf_file).ref();
71 }
72
73 // FIXME:JK if we had a link from Atom to parent AtomList we would not need to update Atom's value or osec index
74 for (list.atoms.items) |ref| {
75 const atom_ptr = elf_file.atom(ref).?;
76 atom_ptr.output_section_index = list.output_section_index;
77 atom_ptr.value += list.value;
78 }
79}
80
81pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void {
82 const gpa = elf_file.base.comp.gpa;
83 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
84 assert(osec.sh_type != elf.SHT_NOBITS);
85
86 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
87
88 try buffer.ensureUnusedCapacity(list.size);
89 buffer.appendNTimesAssumeCapacity(0, list.size);
90
91 for (list.atoms.items) |ref| {
92 const atom_ptr = elf_file.atom(ref).?;
93 assert(atom_ptr.alive);
94
95 const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
96 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
97
98 log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
99
100 const object = atom_ptr.file(elf_file).?.object;
101 const code = try object.codeDecompressAlloc(elf_file, ref.index);
102 defer gpa.free(code);
103 const out_code = buffer.items[off..][0..size];
104 @memcpy(out_code, code);
105
106 if (osec.sh_flags & elf.SHF_ALLOC == 0)
107 try atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, undefs)
108 else
109 try atom_ptr.resolveRelocsAlloc(elf_file, out_code);
110 }
111
112 try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));
113 buffer.clearRetainingCapacity();
114}
115
116pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *Elf) !void {
117 const gpa = elf_file.base.comp.gpa;
118 const osec = elf_file.sections.items(.shdr)[list.output_section_index];
119 assert(osec.sh_type != elf.SHT_NOBITS);
120
121 log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)});
122
123 try buffer.ensureUnusedCapacity(list.size);
124 buffer.appendNTimesAssumeCapacity(0, list.size);
125
126 for (list.atoms.items) |ref| {
127 const atom_ptr = elf_file.atom(ref).?;
128 assert(atom_ptr.alive);
129
130 const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow;
131 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
132
133 log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off });
134
135 const object = atom_ptr.file(elf_file).?.object;
136 const code = try object.codeDecompressAlloc(elf_file, ref.index);
137 defer gpa.free(code);
138 const out_code = buffer.items[off..][0..size];
139 @memcpy(out_code, code);
140 }
141
142 try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file));
143 buffer.clearRetainingCapacity();
144}
145
146pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom {
147 assert(list.atoms.items.len > 0);
148 return elf_file.atom(list.atoms.items[0]).?;
149}
150
151pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom {
152 assert(list.atoms.items.len > 0);
153 return elf_file.atom(list.atoms.items[list.atoms.items.len - 1]).?;
154}
155
156pub fn format(
157 list: AtomList,
158 comptime unused_fmt_string: []const u8,
159 options: std.fmt.FormatOptions,
160 writer: anytype,
161) !void {
162 _ = list;
163 _ = unused_fmt_string;
164 _ = options;
165 _ = writer;
166 @compileError("do not format AtomList directly");
167}
168
169const FormatCtx = struct { AtomList, *Elf };
170
171pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) {
172 return .{ .data = .{ list, elf_file } };
173}
174
175fn format2(
176 ctx: FormatCtx,
177 comptime unused_fmt_string: []const u8,
178 options: std.fmt.FormatOptions,
179 writer: anytype,
180) !void {
181 _ = unused_fmt_string;
182 _ = options;
183 const list, const elf_file = ctx;
184 try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{
185 list.address(elf_file), list.output_section_index,
186 list.alignment.toByteUnits() orelse 0, list.size,
187 });
188 try writer.writeAll(" : atoms{ ");
189 for (list.atoms.items, 0..) |ref, i| {
190 try writer.print("{}", .{ref});
191 if (i < list.atoms.items.len - 1) try writer.writeAll(", ");
192 }
193 try writer.writeAll(" }");
194}
195
196const assert = std.debug.assert;
197const elf = std.elf;
198const log = std.log.scoped(.link);
199const math = std.math;
200const std = @import("std");
201
202const Allocator = std.mem.Allocator;
203const Atom = @import("Atom.zig");
204const AtomList = @This();
205const Elf = @import("../Elf.zig");
206const Object = @import("Object.zig");