diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2020-12-18 17:22:12 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2020-12-19 12:19:00 +0100 |
| commit | 99578e828b84ba7b308e7bbfac3e99650379edc0 (patch) | |
| tree | 0e61bcf5e69bd18ecb1bcc8e5aa4925b3ce35753 /src | |
| parent | 6a021d845a78241415c1f8537cb8ae63a8367b89 (diff) | |
| download | zig-99578e828b84ba7b308e7bbfac3e99650379edc0.tar.gz zig-99578e828b84ba7b308e7bbfac3e99650379edc0.zip | |
macho: move findFreeSpace back to MachO struct
However, adding a twist where `findFreeSpace` accepts a `SegmentCommand`
as argument meaning we want to look for free space specifically within
that segment and nowhere else.
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 76 | ||||
| -rw-r--r-- | src/link/MachO/commands.zig | 33 |
2 files changed, 51 insertions, 58 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 91a1e422fd..8687e44ec5 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -152,8 +152,8 @@ pub const PieFixup = struct { }; /// `alloc_num / alloc_den` is the factor of padding when allocating. -pub const alloc_num = 4; -pub const alloc_den = 3; +const alloc_num = 4; +const alloc_den = 3; /// Default path to dyld /// TODO instead of hardcoding it, we should probably look through some env vars and search paths @@ -1305,21 +1305,21 @@ pub fn populateMissingMetadata(self: *MachO) !void { log.debug("found __TEXT segment free space 0x{x} to 0x{x}\n", .{ 0, needed_size }); - var segment = SegmentCommand.empty(.{ - .cmd = macho.LC_SEGMENT_64, - .cmdsize = @sizeOf(macho.segment_command_64), - .segname = makeStaticString("__TEXT"), - .vmaddr = 0x100000000, // always starts at 4GB - .vmsize = needed_size, - .fileoff = 0, - .filesize = needed_size, - .maxprot = maxprot, - .initprot = initprot, - .nsects = 0, - .flags = 0, + try self.load_commands.append(self.base.allocator, .{ + .Segment = SegmentCommand.empty(.{ + .cmd = macho.LC_SEGMENT_64, + .cmdsize = @sizeOf(macho.segment_command_64), + .segname = makeStaticString("__TEXT"), + .vmaddr = 0x100000000, // always starts at 4GB + .vmsize = needed_size, + .fileoff = 0, + .filesize = needed_size, + .maxprot = maxprot, + .initprot = initprot, + .nsects = 0, + .flags = 0, + }), }); - segment.header_pad = self.header_pad; - try self.load_commands.append(self.base.allocator, .{ .Segment = segment }); self.cmd_table_dirty = true; } if (self.text_section_index == null) { @@ -1333,7 +1333,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { }; const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; const needed_size = self.base.options.program_code_size_hint; - const off = text_segment.findFreeSpace(needed_size, @as(u16, 1) << alignment); + const off = self.findFreeSpace(text_segment, needed_size, @as(u16, 1) << alignment); log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); @@ -1342,7 +1342,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { .segname = makeStaticString("__TEXT"), .addr = text_segment.inner.vmaddr + off, .size = @intCast(u32, needed_size), - .offset = off, + .offset = @intCast(u32, off), .@"align" = alignment, .reloff = 0, .nreloc = 0, @@ -1360,10 +1360,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS; const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint; - const off = text_segment.findFreeSpace(needed_size, @sizeOf(u64)); - - // TODO Audit this. Is it possible to not find free space? We need to grow __TEXT then. - assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); + const off = self.findFreeSpace(text_segment, needed_size, @sizeOf(u64)); + assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment. log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size }); @@ -1372,7 +1370,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { .segname = makeStaticString("__TEXT"), .addr = text_segment.inner.vmaddr + off, .size = needed_size, - .offset = off, + .offset = @intCast(u32, off), .@"align" = @sizeOf(u64), .reloff = 0, .nreloc = 0, @@ -1725,6 +1723,32 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { }; } +fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 { + const end = start + satMul(size, alloc_num) / alloc_den; + for (segment.sections.items) |section| { + const increased_size = satMul(section.size, alloc_num) / alloc_den; + const test_end = section.offset + increased_size; + if (end > section.offset and start < test_end) { + return test_end; + } + } + return null; +} + +fn findFreeSpace(self: *MachO, segment: *const SegmentCommand, object_size: u64, min_alignment: u16) u64 { + var start: u64 = if (parseAndCmpName(&segment.inner.segname, "__TEXT")) self.header_pad else 0; + while (self.detectAllocCollision(segment, start, object_size)) |item_end| { + start = mem.alignForwardGeneric(u64, item_end, min_alignment); + } + return start; +} + +/// Saturating multiplication +fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { + const T = @TypeOf(a, b); + return std.math.mul(T, a, b) catch std.math.maxInt(T); +} + fn writeOffsetTableEntry(self: *MachO, index: usize) !void { const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; const sect = &text_semgent.sections.items[self.got_section_index.?]; @@ -2140,9 +2164,3 @@ fn parseLazyBindingInfoTable(self: *MachO) !void { var stream = std.io.fixedBufferStream(buffer); try self.lazy_binding_info_table.read(stream.reader(), self.base.allocator); } - -/// Saturating multiplication -pub fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { - const T = @TypeOf(a, b); - return std.math.mul(T, a, b) catch std.math.maxInt(T); -} diff --git a/src/link/MachO/commands.zig b/src/link/MachO/commands.zig index cb7487f3d0..bf63722ece 100644 --- a/src/link/MachO/commands.zig +++ b/src/link/MachO/commands.zig @@ -7,11 +7,7 @@ const macho = std.macho; const testing = std.testing; const Allocator = std.mem.Allocator; -const MachO = @import("../MachO.zig"); -const makeName = MachO.makeStaticString; -const alloc_num = MachO.alloc_num; -const alloc_den = MachO.alloc_den; -const satMul = MachO.satMul; +const makeStaticString = @import("../MachO.zig").makeStaticString; pub const LoadCommand = union(enum) { Segment: SegmentCommand, @@ -153,7 +149,6 @@ pub const LoadCommand = union(enum) { pub const SegmentCommand = struct { inner: macho.segment_command_64, - header_pad: ?u64 = null, sections: std.ArrayListUnmanaged(macho.section_64) = .{}, pub fn empty(inner: macho.segment_command_64) SegmentCommand { @@ -166,26 +161,6 @@ pub const SegmentCommand = struct { self.inner.nsects += 1; } - fn detectAllocCollision(self: SegmentCommand, start: u64, size: u64) ?u64 { - const end = start + satMul(size, alloc_num) / alloc_den; - for (self.sections.items) |section| { - const increased_size = satMul(section.size, alloc_num) / alloc_den; - const test_end = section.offset + increased_size; - if (end > section.offset and start < test_end) { - return test_end; - } - } - return null; - } - - pub fn findFreeSpace(self: SegmentCommand, object_size: u64, min_alignment: u16) u32 { - var start: u64 = if (self.header_pad) |pad| pad else 0; - while (self.detectAllocCollision(start, object_size)) |item_end| { - start = mem.alignForwardGeneric(u64, item_end, min_alignment); - } - return @intCast(u32, start); - } - pub fn read(alloc: *Allocator, reader: anytype) !SegmentCommand { const inner = try reader.readStruct(macho.segment_command_64); var segment = SegmentCommand{ @@ -308,7 +283,7 @@ test "read-write segment command" { .inner = .{ .cmd = macho.LC_SEGMENT_64, .cmdsize = 152, - .segname = makeName("__TEXT"), + .segname = makeStaticString("__TEXT"), .vmaddr = 4294967296, .vmsize = 294912, .fileoff = 0, @@ -320,8 +295,8 @@ test "read-write segment command" { }, }; try cmd.sections.append(gpa, .{ - .sectname = makeName("__text"), - .segname = makeName("__TEXT"), + .sectname = makeStaticString("__text"), + .segname = makeStaticString("__TEXT"), .addr = 4294983680, .size = 448, .offset = 16384, |
