authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-01 16:32:09+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-01 16:32:09+01:00
log5bffc17c42bb6eacd0cc09a61954e98ccf912fa4
tree410cb2ab56760fd80ed04d8706fceef3fba00fdd
parent00016ab6a0bd31bed77c86074a6666822b8d0f20

codegen: make LinkerLoad a common struct shared by backends


4 files changed, 57 insertions(+), 160 deletions(-)

src/arch/aarch64/CodeGen.zig+31-145
......@@ -146,11 +146,8 @@ const MCValue = union(enum) {
146146 /// If the type is a pointer, it means the pointer address is at
147147 /// this memory location.
148148 memory: u64,
149 /// The value is in memory but requires a linker relocation fixup:
150 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
151 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
152 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
153 linker_load: struct { type: enum { got, direct, import }, sym_index: u32 },
149 /// The value is in memory but requires a linker relocation fixup.
150 linker_load: codegen.LinkerLoad,
154151 /// The value is one of the stack variables.
155152 ///
156153 /// If the type is a pointer, it means the pointer address is in
......@@ -217,33 +214,23 @@ const DbgInfoReloc = struct {
217214 }
218215
219216 fn genVarDbgInfo(reloc: DbgInfoReloc, function: Self) !void {
220 const name_with_null = reloc.name.ptr[0 .. reloc.name.len + 1];
221 const ty = switch (reloc.tag) {
222 .dbg_var_ptr => reloc.ty.childType(),
223 .dbg_var_val => reloc.ty,
217 const is_ptr = switch (reloc.tag) {
218 .dbg_var_ptr => true,
219 .dbg_var_val => false,
224220 else => unreachable,
225221 };
226 // const atom= function.getDbgInfoAtomPtr();
222 const atom = function.getDbgInfoAtomPtr();
227223
228224 switch (function.debug_output) {
229225 .dwarf => |dw| {
230 const dbg_info = &dw.dbg_info;
231 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
232 const endian = function.target.cpu.arch.endian();
233
234 switch (reloc.mcv) {
235 .register => |reg| {
236 try dbg_info.ensureUnusedCapacity(2);
237 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
238 1, // ULEB128 dwarf expression length
239 reg.dwarfLocOp(),
240 });
226 const loc: link.File.Dwarf.DeclState.VarArgDbgInfoLoc = switch (reloc.mcv) {
227 .register => |reg| .{
228 .register = reg.dwarfLocOp(),
241229 },
242
243230 .ptr_stack_offset,
244231 .stack_offset,
245232 .stack_argument_offset,
246 => |offset| {
233 => |offset| blk: {
247234 const adjusted_offset = switch (reloc.mcv) {
248235 .ptr_stack_offset,
249236 .stack_offset,
......@@ -251,110 +238,31 @@ const DbgInfoReloc = struct {
251238 .stack_argument_offset => @intCast(i32, function.saved_regs_stack_space + offset),
252239 else => unreachable,
253240 };
254
255 try dbg_info.ensureUnusedCapacity(7);
256 const fixup = dbg_info.items.len;
257 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
258 1, // we will backpatch it after we encode the displacement in LEB128
259 Register.x29.dwarfLocOpDeref(), // frame pointer
260 });
261 leb128.writeILEB128(dbg_info.writer(), adjusted_offset) catch unreachable;
262 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
263 },
264
265 .memory,
266 .linker_load,
267 => {
268 const ptr_width = @intCast(u8, @divExact(function.target.cpu.arch.ptrBitWidth(), 8));
269 const is_ptr = switch (reloc.tag) {
270 .dbg_var_ptr => true,
271 .dbg_var_val => false,
272 else => unreachable,
273 };
274 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
275 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
276 1 + ptr_width + @boolToInt(is_ptr),
277 DW.OP.addr, // literal address
278 });
279 const offset = @intCast(u32, dbg_info.items.len);
280 const addr = switch (reloc.mcv) {
281 .memory => |addr| addr,
282 else => 0,
283 };
284 switch (ptr_width) {
285 0...4 => {
286 try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
241 break :blk .{
242 .stack = .{
243 .fp_register = Register.x29.dwarfLocOpDeref(),
244 .offset = adjusted_offset,
287245 },
288 5...8 => {
289 try dbg_info.writer().writeInt(u64, addr, endian);
290 },
291 else => unreachable,
292 }
293 if (is_ptr) {
294 // We need deref the address as we point to the value via GOT entry.
295 try dbg_info.append(DW.OP.deref);
296 }
297 switch (reloc.mcv) {
298 .linker_load => |load_struct| try dw.addExprlocReloc(
299 load_struct.sym_index,
300 offset,
301 is_ptr,
302 ),
303 else => {},
304 }
305 },
306
307 .immediate => |x| {
308 try dbg_info.ensureUnusedCapacity(2);
309 const fixup = dbg_info.items.len;
310 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
311 1,
312 if (ty.isSignedInt()) DW.OP.consts else DW.OP.constu,
313 });
314 if (ty.isSignedInt()) {
315 try leb128.writeILEB128(dbg_info.writer(), @bitCast(i64, x));
316 } else {
317 try leb128.writeULEB128(dbg_info.writer(), x);
318 }
319 try dbg_info.append(DW.OP.stack_value);
320 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
321 },
322
323 .undef => {
324 // DW.AT.location, DW.FORM.exprloc
325 // uleb128(exprloc_len)
326 // DW.OP.implicit_value uleb128(len_of_bytes) bytes
327 const abi_size = @intCast(u32, ty.abiSize(function.target.*));
328 var implicit_value_len = std.ArrayList(u8).init(function.gpa);
329 defer implicit_value_len.deinit();
330 try leb128.writeULEB128(implicit_value_len.writer(), abi_size);
331 const total_exprloc_len = 1 + implicit_value_len.items.len + abi_size;
332 try leb128.writeULEB128(dbg_info.writer(), total_exprloc_len);
333 try dbg_info.ensureUnusedCapacity(total_exprloc_len);
334 dbg_info.appendAssumeCapacity(DW.OP.implicit_value);
335 dbg_info.appendSliceAssumeCapacity(implicit_value_len.items);
336 dbg_info.appendNTimesAssumeCapacity(0xaa, abi_size);
337 },
338
339 .none => {
340 try dbg_info.ensureUnusedCapacity(3);
341 dbg_info.appendSliceAssumeCapacity(&[3]u8{ // DW.AT.location, DW.FORM.exprloc
342 2, DW.OP.lit0, DW.OP.stack_value,
343 });
246 };
344247 },
345
346 else => {
347 try dbg_info.ensureUnusedCapacity(2);
348 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
349 1, DW.OP.nop,
350 });
248 .memory => |address| .{ .memory = .{
249 .address = address,
250 .is_ptr = is_ptr,
251 } },
252 .linker_load => |linker_load| .{ .memory = .{
253 .address = 0,
254 .is_ptr = is_ptr,
255 .linker_load = linker_load,
256 } },
257 .immediate => |x| .{ .immediate = x },
258 .undef => .undef,
259 .none => .none,
260 else => blk: {
351261 log.debug("TODO generate debug info for {}", .{reloc.mcv});
262 break :blk .nop;
352263 },
353 }
354
355 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
356 try function.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
357 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
264 };
265 try dw.genVarDbgInfo(reloc.name, reloc.ty, atom, loc);
358266 },
359267 .plan9 => {},
360268 .none => {},
......@@ -1071,28 +979,6 @@ fn ensureProcessDeathCapacity(self: *Self, additional_count: usize) !void {
1071979 try table.ensureUnusedCapacity(self.gpa, additional_count);
1072980}
1073981
1074/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
1075/// after codegen for this symbol is done.
1076fn addDbgInfoTypeReloc(self: Self, ty: Type) !void {
1077 switch (self.debug_output) {
1078 .dwarf => |dw| {
1079 const dbg_info = &dw.dbg_info;
1080 const index = dbg_info.items.len;
1081 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
1082 const mod = self.bin_file.options.module.?;
1083 const fn_owner_decl = mod.declPtr(self.mod_fn.owner_decl);
1084 const atom = switch (self.bin_file.tag) {
1085 .elf => &fn_owner_decl.link.elf.dbg_info_atom,
1086 .macho => &fn_owner_decl.link.macho.dbg_info_atom,
1087 else => unreachable,
1088 };
1089 try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index));
1090 },
1091 .plan9 => {},
1092 .none => {},
1093 }
1094}
1095
1096982fn allocMem(
1097983 self: *Self,
1098984 abi_size: u32,
src/arch/x86_64/CodeGen.zig+11-11
......@@ -128,11 +128,8 @@ pub const MCValue = union(enum) {
128128 /// The value is in memory at a hard-coded address.
129129 /// If the type is a pointer, it means the pointer address is at this memory location.
130130 memory: u64,
131 /// The value is in memory but requires a linker relocation fixup:
132 /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
133 /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
134 /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
135 linker_load: struct { type: enum { got, direct, import }, sym_index: u32 },
131 /// The value is in memory but requires a linker relocation fixup.
132 linker_load: codegen.LinkerLoad,
136133 /// The value is one of the stack variables.
137134 /// If the type is a pointer, it means the pointer address is in the stack at this offset.
138135 stack_offset: i32,
......@@ -3865,12 +3862,15 @@ fn genVarDbgInfo(
38653862 .fp_register = Register.rbp.dwarfLocOpDeref(),
38663863 .offset = -off,
38673864 } },
3868 .memory => |address| .{
3869 .memory = .{
3870 .address = address,
3871 .is_ptr = is_ptr,
3872 },
3873 },
3865 .memory => |address| .{ .memory = .{
3866 .address = address,
3867 .is_ptr = is_ptr,
3868 } },
3869 .linker_load => |linker_load| .{ .memory = .{
3870 .address = 0,
3871 .is_ptr = is_ptr,
3872 .linker_load = linker_load,
3873 } },
38743874 .immediate => |x| .{ .immediate = x },
38753875 .undef => .undef,
38763876 .none => .none,
src/codegen.zig+13
......@@ -68,6 +68,19 @@ pub const DebugInfoOutput = union(enum) {
6868 none,
6969};
7070
71/// Helper struct to denote that the value is in memory but requires a linker relocation fixup:
72/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
73/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
74/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
75pub const LinkerLoad = struct {
76 type: enum {
77 got,
78 direct,
79 import,
80 },
81 sym_index: u32,
82};
83
7184pub fn generateFunction(
7285 bin_file: *link.File,
7386 src_loc: Module.SrcLoc,
src/link/Dwarf.zig+2-4
......@@ -16,6 +16,7 @@ const DW = std.dwarf;
1616const File = link.File;
1717const LinkBlock = File.LinkBlock;
1818const LinkFn = File.LinkFn;
19const LinkerLoad = @import("../codegen.zig").LinkerLoad;
1920const Module = @import("../Module.zig");
2021const Value = @import("../value.zig").Value;
2122const Type = @import("../type.zig").Type;
......@@ -616,10 +617,7 @@ pub const DeclState = struct {
616617 memory: struct {
617618 address: u64,
618619 is_ptr: bool,
619 linker_load: ?struct {
620 type: enum { got, direct, import },
621 sym_index: u32,
622 } = null,
620 linker_load: ?LinkerLoad = null,
623621 },
624622 immediate: u64,
625623 undef,