macho: implement more self-hosted primitives

This commit is contained in:
Jakub Konka 2024-01-18 14:59:15 +01:00
parent 55c8b82b50
commit 2169a5559d
3 changed files with 164 additions and 16 deletions

View File

@ -20,6 +20,7 @@ sections: std.MultiArrayList(Section) = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
globals: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
/// This table will be populated after `scanRelocs` has run.
/// Key is symbol index.
@ -327,6 +328,7 @@ pub fn deinit(self: *MachO) void {
self.symbols.deinit(gpa);
self.symbols_extra.deinit(gpa);
self.symbols_free_list.deinit(gpa);
self.globals.deinit(gpa);
{
var it = self.undefs.iterator();
@ -3260,9 +3262,8 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
}
pub fn growSection(self: *MachO, sect_index: u8, size: u64) !void {
_ = self;
_ = sect_index;
_ = size;
const sect = &self.sections.items(.header)[sect_index];
std.debug.print("curr={x}, needed={x}\n", .{ sect.size, size });
@panic("TODO growSection");
}

View File

@ -324,6 +324,70 @@ pub fn grow(self: *Atom, macho_file: *MachO) !void {
try self.allocate(macho_file);
}
pub fn free(self: *Atom, macho_file: *MachO) void {
log.debug("freeAtom {d} ({s})", .{ self.atom_index, self.getName(macho_file) });
const comp = macho_file.base.comp;
const gpa = comp.gpa;
const free_list = &macho_file.sections.items(.free_list)[self.out_n_sect];
const last_atom_index = &macho_file.sections.items(.last_atom_index)[self.out_n_sect];
var already_have_free_list_node = false;
{
var i: usize = 0;
// TODO turn free_list into a hash map
while (i < free_list.items.len) {
if (free_list.items[i] == self.atom_index) {
_ = free_list.swapRemove(i);
continue;
}
if (free_list.items[i] == self.prev_index) {
already_have_free_list_node = true;
}
i += 1;
}
}
if (macho_file.getAtom(last_atom_index.*)) |last_atom| {
if (last_atom.atom_index == self.atom_index) {
if (macho_file.getAtom(self.prev_index)) |_| {
// TODO shrink the section size here
last_atom_index.* = self.prev_index;
} else {
last_atom_index.* = 0;
}
}
}
if (macho_file.getAtom(self.prev_index)) |prev| {
prev.next_index = self.next_index;
if (!already_have_free_list_node and prev.*.freeListEligible(macho_file)) {
// The free list is heuristics, it doesn't have to be perfect, so we can
// ignore the OOM here.
free_list.append(gpa, prev.atom_index) catch {};
}
} else {
self.prev_index = 0;
}
if (macho_file.getAtom(self.next_index)) |next| {
next.prev_index = self.prev_index;
} else {
self.next_index = 0;
}
// TODO create relocs free list
self.freeRelocs(macho_file);
// TODO figure out how to free input section mappind in ZigModule
// const zig_object = macho_file.zigObjectPtr().?
// assert(zig_object.atoms.swapRemove(self.atom_index));
self.* = .{};
}
pub fn freeRelocs(self: *Atom, macho_file: *MachO) void {
self.getFile(macho_file).zig_object.freeAtomRelocs(self.*);
self.relocs.len = 0;
}
pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();

View File

@ -129,6 +129,10 @@ pub fn getAtomRelocs(self: *ZigObject, atom: Atom) []const Relocation {
return relocs.items[0..atom.relocs.len];
}
pub fn freeAtomRelocs(self: *ZigObject, atom: Atom) void {
self.relocs.items[atom.relocs.pos].clearRetainingCapacity();
}
pub fn resolveSymbols(self: *ZigObject, macho_file: *MachO) void {
_ = self;
_ = macho_file;
@ -263,11 +267,42 @@ pub fn lowerAnonDecl(
@panic("TODO lowerAnonDecl");
}
pub fn freeDecl(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
const gpa = macho_file.base.comp.gpa;
const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
for (unnamed_consts.items) |sym_index| {
self.freeDeclMetadata(macho_file, sym_index);
}
unnamed_consts.clearAndFree(gpa);
}
fn freeDeclMetadata(self: *ZigObject, macho_file: *MachO, sym_index: Symbol.Index) void {
_ = self;
_ = macho_file;
_ = decl_index;
@panic("TODO freeDecl");
const gpa = macho_file.base.comp.gpa;
const sym = macho_file.getSymbol(sym_index);
sym.getAtom(macho_file).?.free(macho_file);
log.debug("adding %{d} to local symbols free list", .{sym_index});
macho_file.symbols_free_list.append(gpa, sym_index) catch {};
macho_file.symbols.items[sym_index] = .{};
// TODO free GOT entry here
}
pub fn freeDecl(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
log.debug("freeDecl {*}", .{decl});
if (self.decls.fetchRemove(decl_index)) |const_kv| {
var kv = const_kv;
const sym_index = kv.value.symbol_index;
self.freeDeclMetadata(macho_file, sym_index);
self.freeUnnamedConsts(macho_file, decl_index);
kv.value.exports.deinit(gpa);
}
// TODO free decl in dSYM
}
pub fn updateFunc(
@ -278,13 +313,61 @@ pub fn updateFunc(
air: Air,
liveness: Liveness,
) !void {
_ = self;
_ = macho_file;
_ = mod;
_ = func_index;
_ = air;
_ = liveness;
@panic("TODO updateFunc");
const tracy = trace(@src());
defer tracy.end();
const gpa = macho_file.base.comp.gpa;
const func = mod.funcInfo(func_index);
const decl_index = func.owner_decl;
const decl = mod.declPtr(decl_index);
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
self.freeUnnamedConsts(macho_file, decl_index);
macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
var decl_state: ?Dwarf.DeclState = null; // TODO: Dwarf
defer if (decl_state) |*ds| ds.deinit();
const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
const res = try codegen.generateFunction(
&macho_file.base,
decl.srcLoc(mod),
func_index,
air,
liveness,
&code_buffer,
dio,
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_decls.put(mod.gpa, decl_index, em);
return;
},
};
const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
try self.updateDeclCode(macho_file, decl_index, sym_index, sect_index, code);
// if (decl_state) |*ds| {
// const sym = elf_file.symbol(sym_index);
// try self.dwarf.?.commitDeclState(
// mod,
// decl_index,
// sym.value,
// sym.atom(elf_file).?.size,
// ds,
// );
// }
// Since we updated the vaddr and the size, each corresponding export
// symbol also needs to be updated.
return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
}
pub fn updateDecl(
@ -313,7 +396,7 @@ pub fn updateDecl(
}
const sym_index = try self.getOrCreateMetadataForDecl(macho_file, decl_index);
// TODO: free relocs if any
macho_file.getSymbol(sym_index).getAtom(macho_file).?.freeRelocs(macho_file);
const gpa = macho_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
@ -431,7 +514,7 @@ fn updateDeclCode(
}
} else {
try atom.allocate(macho_file);
// TODO: freeDeclMetadata in case of error
errdefer self.freeDeclMetadata(macho_file, sym_index);
sym.value = 0;
sym.flags.needs_zig_got = true;