mirror of
https://github.com/ziglang/zig.git
synced 2025-12-27 08:33:15 +00:00
stage2: make link data in Decl into unions
This will allow for implementation of non-Elf backends without wasting memory.
This commit is contained in:
parent
a2bb246db4
commit
2fc18b5278
@ -177,14 +177,14 @@ pub const Decl = struct {
|
||||
|
||||
/// Represents the position of the code in the output file.
|
||||
/// This is populated regardless of semantic analysis and code generation.
|
||||
link: link.File.Elf.TextBlock = link.File.Elf.TextBlock.empty,
|
||||
link: link.File.LinkBlock,
|
||||
|
||||
/// Represents the function in the linked output file, if the `Decl` is a function.
|
||||
/// This is stored here and not in `Fn` because `Decl` survives across updates but
|
||||
/// `Fn` does not.
|
||||
/// TODO Look into making `Fn` a longer lived structure and moving this field there
|
||||
/// to save on memory usage.
|
||||
fn_link: link.File.Elf.SrcFn = link.File.Elf.SrcFn.empty,
|
||||
fn_link: link.File.LinkFn,
|
||||
|
||||
contents_hash: std.zig.SrcHash,
|
||||
|
||||
@ -1538,10 +1538,13 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void {
|
||||
if (!srcHashEql(decl.contents_hash, contents_hash)) {
|
||||
try self.markOutdatedDecl(decl);
|
||||
decl.contents_hash = contents_hash;
|
||||
} else if (decl.fn_link.len != 0) {
|
||||
// TODO Look into detecting when this would be unnecessary by storing enough state
|
||||
// in `Decl` to notice that the line number did not change.
|
||||
self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
|
||||
} else switch (self.bin_file.tag) {
|
||||
.elf => if (decl.fn_link.elf.len != 0) {
|
||||
// TODO Look into detecting when this would be unnecessary by storing enough state
|
||||
// in `Decl` to notice that the line number did not change.
|
||||
self.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
|
||||
},
|
||||
.c => {},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -1745,7 +1748,14 @@ fn allocateNewDecl(
|
||||
.analysis = .unreferenced,
|
||||
.deletion_flag = false,
|
||||
.contents_hash = contents_hash,
|
||||
.link = link.File.Elf.TextBlock.empty,
|
||||
.link = switch (self.bin_file.tag) {
|
||||
.elf => .{ .elf = link.File.Elf.TextBlock.empty },
|
||||
.c => .{ .c = {} },
|
||||
},
|
||||
.fn_link = switch (self.bin_file.tag) {
|
||||
.elf => .{ .elf = link.File.Elf.SrcFn.empty },
|
||||
.c => .{ .c = {} },
|
||||
},
|
||||
.generation = 0,
|
||||
};
|
||||
return new_decl;
|
||||
|
||||
@ -145,10 +145,10 @@ pub fn generateSymbol(
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
|
||||
const decl = payload.decl;
|
||||
if (decl.analysis != .complete) return error.AnalysisFail;
|
||||
assert(decl.link.local_sym_index != 0);
|
||||
assert(decl.link.elf.local_sym_index != 0);
|
||||
// TODO handle the dependency of this symbol on the decl's vaddr.
|
||||
// If the decl changes vaddr, then this symbol needs to get regenerated.
|
||||
const vaddr = bin_file.local_symbols.items[decl.link.local_sym_index].st_value;
|
||||
const vaddr = bin_file.local_symbols.items[decl.link.elf.local_sym_index].st_value;
|
||||
const endian = bin_file.base.options.target.cpu.arch.endian();
|
||||
switch (bin_file.base.options.target.cpu.arch.ptrBitWidth()) {
|
||||
16 => {
|
||||
@ -1085,7 +1085,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
|
||||
// ff 14 25 xx xx xx xx call [addr]
|
||||
try self.code.ensureCapacity(self.code.items.len + 7);
|
||||
self.code.appendSliceAssumeCapacity(&[3]u8{ 0xff, 0x14, 0x25 });
|
||||
@ -1106,7 +1106,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
|
||||
const ptr_bits = self.target.cpu.arch.ptrBitWidth();
|
||||
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.offset_table_index * ptr_bytes);
|
||||
const got_addr = @intCast(u32, got.p_vaddr + func.owner_decl.link.elf.offset_table_index * ptr_bytes);
|
||||
|
||||
try self.genSetReg(inst.base.src, .ra, .{ .memory = got_addr });
|
||||
const jalr = instructions.Jalr{
|
||||
@ -1934,7 +1934,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
|
||||
if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
|
||||
const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
|
||||
const decl = payload.decl;
|
||||
const got_addr = got.p_vaddr + decl.link.offset_table_index * ptr_bytes;
|
||||
const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
|
||||
return MCValue{ .memory = got_addr };
|
||||
}
|
||||
return self.fail(src, "TODO codegen more kinds of const pointers", .{});
|
||||
|
||||
@ -38,6 +38,16 @@ pub const Options = struct {
|
||||
|
||||
|
||||
pub const File = struct {
|
||||
pub const LinkBlock = union {
|
||||
elf: Elf.TextBlock,
|
||||
c: void,
|
||||
};
|
||||
|
||||
pub const LinkFn = union {
|
||||
elf: Elf.SrcFn,
|
||||
c: void,
|
||||
};
|
||||
|
||||
tag: Tag,
|
||||
options: Options,
|
||||
file: ?fs.File,
|
||||
@ -1720,31 +1730,31 @@ pub const File = struct {
|
||||
}
|
||||
|
||||
pub fn allocateDeclIndexes(self: *Elf, decl: *Module.Decl) !void {
|
||||
if (decl.link.local_sym_index != 0) return;
|
||||
if (decl.link.elf.local_sym_index != 0) return;
|
||||
|
||||
try self.local_symbols.ensureCapacity(self.base.allocator, self.local_symbols.items.len + 1);
|
||||
try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
|
||||
|
||||
if (self.local_symbol_free_list.popOrNull()) |i| {
|
||||
log.debug(.link, "reusing symbol index {} for {}\n", .{ i, decl.name });
|
||||
decl.link.local_sym_index = i;
|
||||
decl.link.elf.local_sym_index = i;
|
||||
} else {
|
||||
log.debug(.link, "allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
|
||||
decl.link.local_sym_index = @intCast(u32, self.local_symbols.items.len);
|
||||
decl.link.elf.local_sym_index = @intCast(u32, self.local_symbols.items.len);
|
||||
_ = self.local_symbols.addOneAssumeCapacity();
|
||||
}
|
||||
|
||||
if (self.offset_table_free_list.popOrNull()) |i| {
|
||||
decl.link.offset_table_index = i;
|
||||
decl.link.elf.offset_table_index = i;
|
||||
} else {
|
||||
decl.link.offset_table_index = @intCast(u32, self.offset_table.items.len);
|
||||
decl.link.elf.offset_table_index = @intCast(u32, self.offset_table.items.len);
|
||||
_ = self.offset_table.addOneAssumeCapacity();
|
||||
self.offset_table_count_dirty = true;
|
||||
}
|
||||
|
||||
const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
|
||||
|
||||
self.local_symbols.items[decl.link.local_sym_index] = .{
|
||||
self.local_symbols.items[decl.link.elf.local_sym_index] = .{
|
||||
.st_name = 0,
|
||||
.st_info = 0,
|
||||
.st_other = 0,
|
||||
@ -1752,39 +1762,39 @@ pub const File = struct {
|
||||
.st_value = phdr.p_vaddr,
|
||||
.st_size = 0,
|
||||
};
|
||||
self.offset_table.items[decl.link.offset_table_index] = 0;
|
||||
self.offset_table.items[decl.link.elf.offset_table_index] = 0;
|
||||
}
|
||||
|
||||
pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
|
||||
// Appending to free lists is allowed to fail because the free lists are heuristics based anyway.
|
||||
self.freeTextBlock(&decl.link);
|
||||
if (decl.link.local_sym_index != 0) {
|
||||
self.local_symbol_free_list.append(self.base.allocator, decl.link.local_sym_index) catch {};
|
||||
self.offset_table_free_list.append(self.base.allocator, decl.link.offset_table_index) catch {};
|
||||
self.freeTextBlock(&decl.link.elf);
|
||||
if (decl.link.elf.local_sym_index != 0) {
|
||||
self.local_symbol_free_list.append(self.base.allocator, decl.link.elf.local_sym_index) catch {};
|
||||
self.offset_table_free_list.append(self.base.allocator, decl.link.elf.offset_table_index) catch {};
|
||||
|
||||
self.local_symbols.items[decl.link.local_sym_index].st_info = 0;
|
||||
self.local_symbols.items[decl.link.elf.local_sym_index].st_info = 0;
|
||||
|
||||
decl.link.local_sym_index = 0;
|
||||
decl.link.elf.local_sym_index = 0;
|
||||
}
|
||||
// TODO make this logic match freeTextBlock. Maybe abstract the logic out since the same thing
|
||||
// is desired for both.
|
||||
_ = self.dbg_line_fn_free_list.remove(&decl.fn_link);
|
||||
if (decl.fn_link.prev) |prev| {
|
||||
_ = self.dbg_line_fn_free_list.remove(&decl.fn_link.elf);
|
||||
if (decl.fn_link.elf.prev) |prev| {
|
||||
_ = self.dbg_line_fn_free_list.put(self.base.allocator, prev, {}) catch {};
|
||||
prev.next = decl.fn_link.next;
|
||||
if (decl.fn_link.next) |next| {
|
||||
prev.next = decl.fn_link.elf.next;
|
||||
if (decl.fn_link.elf.next) |next| {
|
||||
next.prev = prev;
|
||||
} else {
|
||||
self.dbg_line_fn_last = prev;
|
||||
}
|
||||
} else if (decl.fn_link.next) |next| {
|
||||
} else if (decl.fn_link.elf.next) |next| {
|
||||
self.dbg_line_fn_first = next;
|
||||
next.prev = null;
|
||||
}
|
||||
if (self.dbg_line_fn_first == &decl.fn_link) {
|
||||
if (self.dbg_line_fn_first == &decl.fn_link.elf) {
|
||||
self.dbg_line_fn_first = null;
|
||||
}
|
||||
if (self.dbg_line_fn_last == &decl.fn_link) {
|
||||
if (self.dbg_line_fn_last == &decl.fn_link.elf) {
|
||||
self.dbg_line_fn_last = null;
|
||||
}
|
||||
}
|
||||
@ -1870,24 +1880,24 @@ pub const File = struct {
|
||||
|
||||
const stt_bits: u8 = if (is_fn) elf.STT_FUNC else elf.STT_OBJECT;
|
||||
|
||||
assert(decl.link.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
|
||||
const local_sym = &self.local_symbols.items[decl.link.local_sym_index];
|
||||
assert(decl.link.elf.local_sym_index != 0); // Caller forgot to allocateDeclIndexes()
|
||||
const local_sym = &self.local_symbols.items[decl.link.elf.local_sym_index];
|
||||
if (local_sym.st_size != 0) {
|
||||
const capacity = decl.link.capacity(self.*);
|
||||
const capacity = decl.link.elf.capacity(self.*);
|
||||
const need_realloc = code.len > capacity or
|
||||
!mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
|
||||
if (need_realloc) {
|
||||
const vaddr = try self.growTextBlock(&decl.link, code.len, required_alignment);
|
||||
const vaddr = try self.growTextBlock(&decl.link.elf, code.len, required_alignment);
|
||||
log.debug(.link, "growing {} from 0x{x} to 0x{x}\n", .{ decl.name, local_sym.st_value, vaddr });
|
||||
if (vaddr != local_sym.st_value) {
|
||||
local_sym.st_value = vaddr;
|
||||
|
||||
log.debug(.link, " (writing new offset table entry)\n", .{});
|
||||
self.offset_table.items[decl.link.offset_table_index] = vaddr;
|
||||
try self.writeOffsetTableEntry(decl.link.offset_table_index);
|
||||
self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
|
||||
try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
|
||||
}
|
||||
} else if (code.len < local_sym.st_size) {
|
||||
self.shrinkTextBlock(&decl.link, code.len);
|
||||
self.shrinkTextBlock(&decl.link.elf, code.len);
|
||||
}
|
||||
local_sym.st_size = code.len;
|
||||
local_sym.st_name = try self.updateString(local_sym.st_name, mem.spanZ(decl.name));
|
||||
@ -1895,13 +1905,13 @@ pub const File = struct {
|
||||
local_sym.st_other = 0;
|
||||
local_sym.st_shndx = self.text_section_index.?;
|
||||
// TODO this write could be avoided if no fields of the symbol were changed.
|
||||
try self.writeSymbol(decl.link.local_sym_index);
|
||||
try self.writeSymbol(decl.link.elf.local_sym_index);
|
||||
} else {
|
||||
const decl_name = mem.spanZ(decl.name);
|
||||
const name_str_index = try self.makeString(decl_name);
|
||||
const vaddr = try self.allocateTextBlock(&decl.link, code.len, required_alignment);
|
||||
const vaddr = try self.allocateTextBlock(&decl.link.elf, code.len, required_alignment);
|
||||
log.debug(.link, "allocated text block for {} at 0x{x}\n", .{ decl_name, vaddr });
|
||||
errdefer self.freeTextBlock(&decl.link);
|
||||
errdefer self.freeTextBlock(&decl.link.elf);
|
||||
|
||||
local_sym.* = .{
|
||||
.st_name = name_str_index,
|
||||
@ -1911,10 +1921,10 @@ pub const File = struct {
|
||||
.st_value = vaddr,
|
||||
.st_size = code.len,
|
||||
};
|
||||
self.offset_table.items[decl.link.offset_table_index] = vaddr;
|
||||
self.offset_table.items[decl.link.elf.offset_table_index] = vaddr;
|
||||
|
||||
try self.writeSymbol(decl.link.local_sym_index);
|
||||
try self.writeOffsetTableEntry(decl.link.offset_table_index);
|
||||
try self.writeSymbol(decl.link.elf.local_sym_index);
|
||||
try self.writeOffsetTableEntry(decl.link.elf.offset_table_index);
|
||||
}
|
||||
|
||||
const section_offset = local_sym.st_value - self.program_headers.items[self.phdr_load_re_index.?].p_vaddr;
|
||||
@ -1941,7 +1951,7 @@ pub const File = struct {
|
||||
// Now we have the full contents and may allocate a region to store it.
|
||||
|
||||
const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
|
||||
const src_fn = &decl.fn_link;
|
||||
const src_fn = &decl.fn_link.elf;
|
||||
src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
|
||||
if (self.dbg_line_fn_last) |last| {
|
||||
if (src_fn.next) |next| {
|
||||
@ -2026,8 +2036,8 @@ pub const File = struct {
|
||||
|
||||
try self.global_symbols.ensureCapacity(self.base.allocator, self.global_symbols.items.len + exports.len);
|
||||
const typed_value = decl.typed_value.most_recent.typed_value;
|
||||
if (decl.link.local_sym_index == 0) return;
|
||||
const decl_sym = self.local_symbols.items[decl.link.local_sym_index];
|
||||
if (decl.link.elf.local_sym_index == 0) return;
|
||||
const decl_sym = self.local_symbols.items[decl.link.elf.local_sym_index];
|
||||
|
||||
for (exports) |exp| {
|
||||
if (exp.options.section) |section_name| {
|
||||
@ -2105,7 +2115,7 @@ pub const File = struct {
|
||||
const casted_line_off = @intCast(u28, line_delta);
|
||||
|
||||
const shdr = &self.sections.items[self.debug_line_section_index.?];
|
||||
const file_pos = shdr.sh_offset + decl.fn_link.off + self.getRelocDbgLineOff();
|
||||
const file_pos = shdr.sh_offset + decl.fn_link.elf.off + self.getRelocDbgLineOff();
|
||||
var data: [4]u8 = undefined;
|
||||
leb128.writeUnsignedFixed(4, &data, casted_line_off);
|
||||
try self.base.file.?.pwriteAll(&data, file_pos);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user