From 618c7a3546bb5e73a4f7ff4bd38e53700f63c90c Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 15 Sep 2022 13:48:00 +0200 Subject: [PATCH] macho: add logic for expanding segments in memory --- src/link/Coff.zig | 1 + src/link/Elf.zig | 1 + src/link/MachO.zig | 43 ++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/link/Coff.zig b/src/link/Coff.zig index d9b887f831..e177c62658 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1135,6 +1135,7 @@ fn getDeclOutputSection(self: *Coff, decl: *Module.Decl) u16 { } switch (zig_ty) { + // TODO: what if this is a function pointer? .Fn => break :blk self.text_section_index.?, else => { if (val.castTag(.variable)) |_| { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index a70473fe07..4e67c095c0 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2320,6 +2320,7 @@ fn getDeclPhdrIndex(self: *Elf, decl: *Module.Decl) !u16 { } switch (zig_ty) { + // TODO: what if this is a function pointer? .Fn => break :blk self.phdr_load_re_index.?, else => { if (val.castTag(.variable)) |_| { diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 6537d926db..2b7a3d43ae 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2839,7 +2839,9 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu const required_alignment = typed_value.ty.abiAlignment(self.base.options.target); atom.size = code.len; atom.alignment = required_alignment; - const sect_id = self.getDeclOutputSection(decl); + // TODO: work out logic for disambiguating functions from function pointers + // const sect_id = self.getDeclOutputSection(decl); + const sect_id = self.data_const_section_index.?; const symbol = atom.getSymbolPtr(self); symbol.n_strx = name_str_index; symbol.n_type = macho.N_SECT; @@ -2956,6 +2958,7 @@ fn getDeclOutputSection(self: *MachO, decl: *Module.Decl) u8 { } switch (zig_ty) { + // TODO: what if this is a function pointer? .Fn => break :blk self.text_section_index.?, else => { if (val.castTag(.variable)) |_| { @@ -3709,6 +3712,41 @@ fn allocateSection(self: *MachO, segname: []const u8, sectname: []const u8, opts return section_id; } +fn moveSectionInVirtualMemory(self: *MachO, sect_id: u32, needed_size: u64) !void { + const header = &self.sections.items(.header)[sect_id]; + const segment = &self.segments.items[self.sections.items(.segment_index)[sect_id]]; + const increased_size = padToIdeal(needed_size); + const old_aligned_end = segment.vmaddr + segment.vmsize; + const new_aligned_end = segment.vmaddr + mem.alignForwardGeneric(u64, increased_size, self.page_size); + const diff = new_aligned_end - old_aligned_end; + log.debug("shifting every segment after {s},{s} in virtual memory by {x}", .{ + header.segName(), + header.sectName(), + diff, + }); + + // TODO: enforce order by increasing VM addresses in self.sections container. + for (self.sections.items(.header)[sect_id + 1 ..]) |*next_header, next_sect_id| { + const index = sect_id + 1 + next_sect_id; + const maybe_last_atom = &self.sections.items(.last_atom)[index]; + const next_segment = &self.segments.items[self.sections.items(.segment_index)[index]]; + next_header.addr += diff; + next_segment.vmaddr += diff; + + if (maybe_last_atom.*) |last_atom| { + var atom = last_atom; + while (true) { + const sym = atom.getSymbolPtr(self); + sym.n_value += diff; + + if (atom.prev) |prev| { + atom = prev; + } else break; + } + } + } +} + fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) !u64 { const tracy = trace(@src()); defer tracy.end(); @@ -3816,13 +3854,12 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64) ! const sect_vm_capacity = self.allocatedVirtualSize(segment.vmaddr); if (needed_size > sect_vm_capacity) { self.markRelocsDirtyByAddress(segment.vmaddr + needed_size); - @panic("TODO grow section in VM"); + try self.moveSectionInVirtualMemory(sect_id, needed_size); } header.size = needed_size; segment.filesize = needed_size; segment.vmsize = mem.alignForwardGeneric(u64, needed_size, self.page_size); - log.warn("updating {s},{s}: {x}, {x}", .{ header.segName(), header.sectName(), segment.vmsize, segment.filesize }); maybe_last_atom.* = atom; self.segment_table_dirty = true;