| author | |
| committer | |
| log | 6337ce16ae76977b2444b5c07f3c436db4d5ece7 |
| tree | f462496a8adce12d5535ab9a0490a2b45ecf1bbb |
| parent | 190ea02e0d0c939c0b558927b63a03e30af4749a |
10 files changed, 394 insertions(+), 295 deletions(-)
src/link/MachO.zig+22-40| ... | @@ -610,7 +610,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -610,7 +610,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 610 | if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately | 610 | if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately |
| 611 | // TODO: we will resolve and write ZigObject's TLS data twice: | 611 | // TODO: we will resolve and write ZigObject's TLS data twice: |
| 612 | // once here, and once in writeAtoms | 612 | // once here, and once in writeAtoms |
| 613 | const code = zo.getAtomDataAlloc(self, gpa, atom.*) catch |err| switch (err) { | 613 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 614 | const code = try gpa.alloc(u8, atom_size); | ||
| 615 | defer gpa.free(code); | ||
| 616 | zo.getAtomData(self, atom.*, code) catch |err| switch (err) { | ||
| 614 | error.InputOutput => { | 617 | error.InputOutput => { |
| 615 | try self.reportUnexpectedError("fetching code for '{s}' failed", .{ | 618 | try self.reportUnexpectedError("fetching code for '{s}' failed", .{ |
| 616 | atom.getName(self), | 619 | atom.getName(self), |
| ... | @@ -625,7 +628,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -625,7 +628,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 625 | return error.FlushFailure; | 628 | return error.FlushFailure; |
| 626 | }, | 629 | }, |
| 627 | }; | 630 | }; |
| 628 | defer gpa.free(code); | ||
| 629 | const file_offset = sect.offset + atom.value - sect.addr; | 631 | const file_offset = sect.offset + atom.value - sect.addr; |
| 630 | atom.resolveRelocs(self, code) catch |err| switch (err) { | 632 | atom.resolveRelocs(self, code) catch |err| switch (err) { |
| 631 | error.ResolveFailed => has_resolve_error = true, | 633 | error.ResolveFailed => has_resolve_error = true, |
| ... | @@ -974,17 +976,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void { | ... | @@ -974,17 +976,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void { |
| 974 | 976 | ||
| 975 | const gpa = self.base.comp.gpa; | 977 | const gpa = self.base.comp.gpa; |
| 976 | const file = try std.fs.cwd().openFile(path, .{}); | 978 | const file = try std.fs.cwd().openFile(path, .{}); |
| 977 | defer file.close(); | ||
| 978 | const mtime: u64 = mtime: { | 979 | const mtime: u64 = mtime: { |
| 979 | const stat = file.stat() catch break :mtime 0; | 980 | const stat = file.stat() catch break :mtime 0; |
| 980 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); | 981 | break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); |
| 981 | }; | 982 | }; |
| 982 | const data = try file.readToEndAlloc(gpa, std.math.maxInt(u32)); | ||
| 983 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 983 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 984 | self.files.set(index, .{ .object = .{ | 984 | self.files.set(index, .{ .object = .{ |
| 985 | .path = try gpa.dupe(u8, path), | 985 | .path = try gpa.dupe(u8, path), |
| 986 | .file = file, | ||
| 986 | .mtime = mtime, | 987 | .mtime = mtime, |
| 987 | .data = data, | ||
| 988 | .index = index, | 988 | .index = index, |
| 989 | } }); | 989 | } }); |
| 990 | try self.objects.append(gpa, index); | 990 | try self.objects.append(gpa, index); |
| ... | @@ -1013,17 +1013,9 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar | ... | @@ -1013,17 +1013,9 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar |
| 1013 | const file = try std.fs.cwd().openFile(lib.path, .{}); | 1013 | const file = try std.fs.cwd().openFile(lib.path, .{}); |
| 1014 | defer file.close(); | 1014 | defer file.close(); |
| 1015 | 1015 | ||
| 1016 | const data = if (fat_arch) |arch| blk: { | 1016 | var archive = Archive{}; |
| 1017 | try file.seekTo(arch.offset); | ||
| 1018 | const data = try gpa.alloc(u8, arch.size); | ||
| 1019 | const nread = try file.readAll(data); | ||
| 1020 | if (nread != arch.size) return error.InputOutput; | ||
| 1021 | break :blk data; | ||
| 1022 | } else try file.readToEndAlloc(gpa, std.math.maxInt(u32)); | ||
| 1023 | |||
| 1024 | var archive = Archive{ .path = try gpa.dupe(u8, lib.path), .data = data }; | ||
| 1025 | defer archive.deinit(gpa); | 1017 | defer archive.deinit(gpa); |
| 1026 | try archive.parse(self); | 1018 | try archive.parse(self, lib.path, file, fat_arch); |
| 1027 | 1019 | ||
| 1028 | var has_parse_error = false; | 1020 | var has_parse_error = false; |
| 1029 | for (archive.objects.items) |extracted| { | 1021 | for (archive.objects.items) |extracted| { |
| ... | @@ -1058,18 +1050,9 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) | ... | @@ -1058,18 +1050,9 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) |
| 1058 | const file = try std.fs.cwd().openFile(lib.path, .{}); | 1050 | const file = try std.fs.cwd().openFile(lib.path, .{}); |
| 1059 | defer file.close(); | 1051 | defer file.close(); |
| 1060 | 1052 | ||
| 1061 | const data = if (fat_arch) |arch| blk: { | ||
| 1062 | try file.seekTo(arch.offset); | ||
| 1063 | const data = try gpa.alloc(u8, arch.size); | ||
| 1064 | const nread = try file.readAll(data); | ||
| 1065 | if (nread != arch.size) return error.InputOutput; | ||
| 1066 | break :blk data; | ||
| 1067 | } else try file.readToEndAlloc(gpa, std.math.maxInt(u32)); | ||
| 1068 | |||
| 1069 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 1053 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1070 | self.files.set(index, .{ .dylib = .{ | 1054 | self.files.set(index, .{ .dylib = .{ |
| 1071 | .path = try gpa.dupe(u8, lib.path), | 1055 | .path = try gpa.dupe(u8, lib.path), |
| 1072 | .data = data, | ||
| 1073 | .index = index, | 1056 | .index = index, |
| 1074 | .needed = lib.needed, | 1057 | .needed = lib.needed, |
| 1075 | .weak = lib.weak, | 1058 | .weak = lib.weak, |
| ... | @@ -1077,7 +1060,7 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) | ... | @@ -1077,7 +1060,7 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch) |
| 1077 | .explicit = explicit, | 1060 | .explicit = explicit, |
| 1078 | } }); | 1061 | } }); |
| 1079 | const dylib = &self.files.items(.data)[index].dylib; | 1062 | const dylib = &self.files.items(.data)[index].dylib; |
| 1080 | try dylib.parse(self); | 1063 | try dylib.parse(self, file, fat_arch); |
| 1081 | 1064 | ||
| 1082 | try self.dylibs.append(gpa, index); | 1065 | try self.dylibs.append(gpa, index); |
| 1083 | 1066 | ||
| ... | @@ -1098,7 +1081,6 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index | ... | @@ -1098,7 +1081,6 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index |
| 1098 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); | 1081 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1099 | self.files.set(index, .{ .dylib = .{ | 1082 | self.files.set(index, .{ .dylib = .{ |
| 1100 | .path = try gpa.dupe(u8, lib.path), | 1083 | .path = try gpa.dupe(u8, lib.path), |
| 1101 | .data = &[0]u8{}, | ||
| 1102 | .index = index, | 1084 | .index = index, |
| 1103 | .needed = lib.needed, | 1085 | .needed = lib.needed, |
| 1104 | .weak = lib.weak, | 1086 | .weak = lib.weak, |
| ... | @@ -1404,6 +1386,8 @@ pub fn resolveSymbols(self: *MachO) !void { | ... | @@ -1404,6 +1386,8 @@ pub fn resolveSymbols(self: *MachO) !void { |
| 1404 | const index = self.objects.items[i]; | 1386 | const index = self.objects.items[i]; |
| 1405 | if (!self.getFile(index).?.object.alive) { | 1387 | if (!self.getFile(index).?.object.alive) { |
| 1406 | _ = self.objects.orderedRemove(i); | 1388 | _ = self.objects.orderedRemove(i); |
| 1389 | self.files.items(.data)[index].object.deinit(self.base.comp.gpa); | ||
| 1390 | self.files.set(index, .null); | ||
| 1407 | } else i += 1; | 1391 | } else i += 1; |
| 1408 | } | 1392 | } |
| 1409 | 1393 | ||
| ... | @@ -1511,18 +1495,13 @@ fn createObjcSections(self: *MachO) !void { | ... | @@ -1511,18 +1495,13 @@ fn createObjcSections(self: *MachO) !void { |
| 1511 | } | 1495 | } |
| 1512 | 1496 | ||
| 1513 | for (objc_msgsend_syms.keys()) |sym_index| { | 1497 | for (objc_msgsend_syms.keys()) |sym_index| { |
| 1498 | const internal = self.getInternalObject().?; | ||
| 1514 | const sym = self.getSymbol(sym_index); | 1499 | const sym = self.getSymbol(sym_index); |
| 1515 | sym.value = 0; | 1500 | _ = try internal.addSymbol(sym.getName(self), self); |
| 1516 | sym.atom = 0; | ||
| 1517 | sym.nlist_idx = 0; | ||
| 1518 | sym.file = self.internal_object.?; | ||
| 1519 | sym.flags = .{}; | ||
| 1520 | sym.visibility = .hidden; | 1501 | sym.visibility = .hidden; |
| 1521 | const object = self.getInternalObject().?; | ||
| 1522 | const name = eatPrefix(sym.getName(self), "_objc_msgSend$").?; | 1502 | const name = eatPrefix(sym.getName(self), "_objc_msgSend$").?; |
| 1523 | const selrefs_index = try object.addObjcMsgsendSections(name, self); | 1503 | const selrefs_index = try internal.addObjcMsgsendSections(name, self); |
| 1524 | try sym.addExtra(.{ .objc_selrefs = selrefs_index }, self); | 1504 | try sym.addExtra(.{ .objc_selrefs = selrefs_index }, self); |
| 1525 | try object.symbols.append(gpa, sym_index); | ||
| 1526 | } | 1505 | } |
| 1527 | } | 1506 | } |
| 1528 | 1507 | ||
| ... | @@ -1659,6 +1638,8 @@ fn deadStripDylibs(self: *MachO) void { | ... | @@ -1659,6 +1638,8 @@ fn deadStripDylibs(self: *MachO) void { |
| 1659 | const index = self.dylibs.items[i]; | 1638 | const index = self.dylibs.items[i]; |
| 1660 | if (!self.getFile(index).?.dylib.isAlive(self)) { | 1639 | if (!self.getFile(index).?.dylib.isAlive(self)) { |
| 1661 | _ = self.dylibs.orderedRemove(i); | 1640 | _ = self.dylibs.orderedRemove(i); |
| 1641 | self.files.items(.data)[index].dylib.deinit(self.base.comp.gpa); | ||
| 1642 | self.files.set(index, .null); | ||
| 1662 | } else i += 1; | 1643 | } else i += 1; |
| 1663 | } | 1644 | } |
| 1664 | } | 1645 | } |
| ... | @@ -2609,13 +2590,13 @@ fn writeAtoms(self: *MachO) !void { | ... | @@ -2609,13 +2590,13 @@ fn writeAtoms(self: *MachO) !void { |
| 2609 | const atom = self.getAtom(atom_index).?; | 2590 | const atom = self.getAtom(atom_index).?; |
| 2610 | assert(atom.flags.alive); | 2591 | assert(atom.flags.alive); |
| 2611 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; | 2592 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; |
| 2612 | const data = switch (atom.getFile(self)) { | ||
| 2613 | .object => |x| try x.getAtomData(atom.*), | ||
| 2614 | .zig_object => |x| try x.getAtomDataAlloc(self, arena.allocator(), atom.*), | ||
| 2615 | else => unreachable, | ||
| 2616 | }; | ||
| 2617 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | 2593 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 2618 | @memcpy(buffer[off..][0..atom_size], data); | 2594 | switch (atom.getFile(self)) { |
| 2595 | .internal => |x| try x.getAtomData(atom.*, buffer[off..][0..atom_size]), | ||
| 2596 | .object => |x| try x.getAtomData(atom.*, buffer[off..][0..atom_size]), | ||
| 2597 | .zig_object => |x| try x.getAtomData(self, atom.*, buffer[off..][0..atom_size]), | ||
| 2598 | else => unreachable, | ||
| 2599 | } | ||
| 2619 | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { | 2600 | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { |
| 2620 | error.ResolveFailed => has_resolve_error = true, | 2601 | error.ResolveFailed => has_resolve_error = true, |
| 2621 | else => |e| return e, | 2602 | else => |e| return e, |
| ... | @@ -3734,6 +3715,7 @@ pub fn getOrCreateGlobal(self: *MachO, off: u32) !GetOrCreateGlobalResult { | ... | @@ -3734,6 +3715,7 @@ pub fn getOrCreateGlobal(self: *MachO, off: u32) !GetOrCreateGlobalResult { |
| 3734 | const index = try self.addSymbol(); | 3715 | const index = try self.addSymbol(); |
| 3735 | const global = self.getSymbol(index); | 3716 | const global = self.getSymbol(index); |
| 3736 | global.name = off; | 3717 | global.name = off; |
| 3718 | global.flags.global = true; | ||
| 3737 | gop.value_ptr.* = index; | 3719 | gop.value_ptr.* = index; |
| 3738 | } | 3720 | } |
| 3739 | return .{ | 3721 | return .{ |
src/link/MachO/Archive.zig+26-18| ... | @@ -1,6 +1,3 @@ | ... | @@ -1,6 +1,3 @@ |
| 1 | path: []const u8, | ||
| 2 | data: []const u8, | ||
| 3 | |||
| 4 | objects: std.ArrayListUnmanaged(Object) = .{}, | 1 | objects: std.ArrayListUnmanaged(Object) = .{}, |
| 5 | 2 | ||
| 6 | // Archive files start with the ARMAG identifying string. Then follows a | 3 | // Archive files start with the ARMAG identifying string. Then follows a |
| ... | @@ -73,62 +70,73 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool { | ... | @@ -73,62 +70,73 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool { |
| 73 | } | 70 | } |
| 74 | 71 | ||
| 75 | pub fn deinit(self: *Archive, allocator: Allocator) void { | 72 | pub fn deinit(self: *Archive, allocator: Allocator) void { |
| 76 | allocator.free(self.data); | ||
| 77 | allocator.free(self.path); | ||
| 78 | self.objects.deinit(allocator); | 73 | self.objects.deinit(allocator); |
| 79 | } | 74 | } |
| 80 | 75 | ||
| 81 | pub fn parse(self: *Archive, macho_file: *MachO) !void { | 76 | pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, file: std.fs.File, fat_arch: ?fat.Arch) !void { |
| 82 | const gpa = macho_file.base.comp.gpa; | 77 | const gpa = macho_file.base.comp.gpa; |
| 83 | 78 | ||
| 84 | var arena = std.heap.ArenaAllocator.init(gpa); | 79 | var arena = std.heap.ArenaAllocator.init(gpa); |
| 85 | defer arena.deinit(); | 80 | defer arena.deinit(); |
| 86 | 81 | ||
| 87 | var stream = std.io.fixedBufferStream(self.data); | 82 | const offset = if (fat_arch) |ar| ar.offset else 0; |
| 88 | const reader = stream.reader(); | 83 | const size = if (fat_arch) |ar| ar.size else (try file.stat()).size; |
| 89 | _ = try reader.readBytesNoEof(SARMAG); | 84 | try file.seekTo(offset); |
| 85 | |||
| 86 | const reader = file.reader(); | ||
| 87 | _ = try reader.readBytesNoEof(Archive.SARMAG); | ||
| 90 | 88 | ||
| 89 | var pos: usize = Archive.SARMAG; | ||
| 91 | while (true) { | 90 | while (true) { |
| 92 | if (stream.pos >= self.data.len) break; | 91 | if (pos >= size) break; |
| 93 | if (!mem.isAligned(stream.pos, 2)) stream.pos += 1; | 92 | if (!mem.isAligned(pos, 2)) { |
| 93 | try file.seekBy(1); | ||
| 94 | pos += 1; | ||
| 95 | } | ||
| 94 | 96 | ||
| 95 | const hdr = try reader.readStruct(ar_hdr); | 97 | const hdr = try reader.readStruct(ar_hdr); |
| 98 | pos += @sizeOf(ar_hdr); | ||
| 96 | 99 | ||
| 97 | if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { | 100 | if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) { |
| 98 | try macho_file.reportParseError(self.path, "invalid header delimiter: expected '{s}', found '{s}'", .{ | 101 | try macho_file.reportParseError(path, "invalid header delimiter: expected '{s}', found '{s}'", .{ |
| 99 | std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), | 102 | std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag), |
| 100 | }); | 103 | }); |
| 101 | return error.MalformedArchive; | 104 | return error.MalformedArchive; |
| 102 | } | 105 | } |
| 103 | 106 | ||
| 104 | var size = try hdr.size(); | 107 | var hdr_size = try hdr.size(); |
| 105 | const name = name: { | 108 | const name = name: { |
| 106 | if (hdr.name()) |n| break :name n; | 109 | if (hdr.name()) |n| break :name n; |
| 107 | if (try hdr.nameLength()) |len| { | 110 | if (try hdr.nameLength()) |len| { |
| 108 | size -= len; | 111 | hdr_size -= len; |
| 109 | const buf = try arena.allocator().alloc(u8, len); | 112 | const buf = try arena.allocator().alloc(u8, len); |
| 110 | try reader.readNoEof(buf); | 113 | try reader.readNoEof(buf); |
| 114 | pos += len; | ||
| 111 | const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; | 115 | const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len; |
| 112 | break :name buf[0..actual_len]; | 116 | break :name buf[0..actual_len]; |
| 113 | } | 117 | } |
| 114 | unreachable; | 118 | unreachable; |
| 115 | }; | 119 | }; |
| 116 | defer { | 120 | defer { |
| 117 | _ = stream.seekBy(size) catch {}; | 121 | _ = file.seekBy(hdr_size) catch {}; |
| 122 | pos += hdr_size; | ||
| 118 | } | 123 | } |
| 119 | 124 | ||
| 120 | if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue; | 125 | if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue; |
| 121 | 126 | ||
| 122 | const object = Object{ | 127 | const object = Object{ |
| 123 | .archive = try gpa.dupe(u8, self.path), | 128 | .archive = .{ |
| 129 | .path = try gpa.dupe(u8, path), | ||
| 130 | .offset = offset + pos, | ||
| 131 | }, | ||
| 124 | .path = try gpa.dupe(u8, name), | 132 | .path = try gpa.dupe(u8, name), |
| 125 | .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]), | 133 | .file = try std.fs.cwd().openFile(path, .{}), |
| 126 | .index = undefined, | 134 | .index = undefined, |
| 127 | .alive = false, | 135 | .alive = false, |
| 128 | .mtime = hdr.date() catch 0, | 136 | .mtime = hdr.date() catch 0, |
| 129 | }; | 137 | }; |
| 130 | 138 | ||
| 131 | log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path }); | 139 | log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path }); |
| 132 | 140 | ||
| 133 | try self.objects.append(gpa, object); | 141 | try self.objects.append(gpa, object); |
| 134 | } | 142 | } |
src/link/MachO/Atom.zig+9-5| ... | @@ -43,7 +43,11 @@ prev_index: Index = 0, | ... | @@ -43,7 +43,11 @@ prev_index: Index = 0, |
| 43 | next_index: Index = 0, | 43 | next_index: Index = 0, |
| 44 | 44 | ||
| 45 | pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 { | 45 | pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 { |
| 46 | return macho_file.strings.getAssumeExists(self.name); | 46 | return switch (self.getFile(macho_file)) { |
| 47 | .dylib => unreachable, | ||
| 48 | .zig_object => |x| x.strtab.getAssumeExists(self.name), | ||
| 49 | inline else => |x| x.getString(self.name), | ||
| 50 | }; | ||
| 47 | } | 51 | } |
| 48 | 52 | ||
| 49 | pub fn getFile(self: Atom, macho_file: *MachO) File { | 53 | pub fn getFile(self: Atom, macho_file: *MachO) File { |
| ... | @@ -52,17 +56,17 @@ pub fn getFile(self: Atom, macho_file: *MachO) File { | ... | @@ -52,17 +56,17 @@ pub fn getFile(self: Atom, macho_file: *MachO) File { |
| 52 | 56 | ||
| 53 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { | 57 | pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation { |
| 54 | return switch (self.getFile(macho_file)) { | 58 | return switch (self.getFile(macho_file)) { |
| 55 | .zig_object => |x| x.getAtomRelocs(self), | 59 | .dylib => unreachable, |
| 56 | .object => |x| x.getAtomRelocs(self), | 60 | inline else => |x| x.getAtomRelocs(self), |
| 57 | else => unreachable, | ||
| 58 | }; | 61 | }; |
| 59 | } | 62 | } |
| 60 | 63 | ||
| 61 | pub fn getInputSection(self: Atom, macho_file: *MachO) macho.section_64 { | 64 | pub fn getInputSection(self: Atom, macho_file: *MachO) macho.section_64 { |
| 62 | return switch (self.getFile(macho_file)) { | 65 | return switch (self.getFile(macho_file)) { |
| 66 | .dylib => unreachable, | ||
| 63 | .zig_object => |x| x.getInputSection(self, macho_file), | 67 | .zig_object => |x| x.getInputSection(self, macho_file), |
| 64 | .object => |x| x.sections.items(.header)[self.n_sect], | 68 | .object => |x| x.sections.items(.header)[self.n_sect], |
| 65 | else => unreachable, | 69 | .internal => |x| x.sections.items(.header)[self.n_sect], |
| 66 | }; | 70 | }; |
| 67 | } | 71 | } |
| 68 | 72 |
src/link/MachO/DwarfInfo.zig+39-20| ... | @@ -1,15 +1,17 @@ | ... | @@ -1,15 +1,17 @@ |
| 1 | debug_info: []const u8, | ||
| 2 | debug_abbrev: []const u8, | ||
| 3 | debug_str: []const u8, | ||
| 4 | |||
| 5 | /// Abbreviation table indexed by offset in the .debug_abbrev bytestream | 1 | /// Abbreviation table indexed by offset in the .debug_abbrev bytestream |
| 6 | abbrev_tables: std.AutoArrayHashMapUnmanaged(u64, AbbrevTable) = .{}, | 2 | abbrev_tables: std.AutoArrayHashMapUnmanaged(u64, AbbrevTable) = .{}, |
| 7 | /// List of compile units as they appear in the .debug_info bytestream | 3 | /// List of compile units as they appear in the .debug_info bytestream |
| 8 | compile_units: std.ArrayListUnmanaged(CompileUnit) = .{}, | 4 | compile_units: std.ArrayListUnmanaged(CompileUnit) = .{}, |
| 9 | 5 | /// Debug info string table | |
| 10 | pub fn init(dw: *DwarfInfo, allocator: Allocator) !void { | 6 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | try dw.parseAbbrevTables(allocator); | 7 | /// Debug info data |
| 12 | try dw.parseCompileUnits(allocator); | 8 | di_data: std.ArrayListUnmanaged(u8) = .{}, |
| 9 | |||
| 10 | pub fn init(dw: *DwarfInfo, allocator: Allocator, di: DebugInfo) !void { | ||
| 11 | try dw.strtab.ensureTotalCapacityPrecise(allocator, di.debug_str.len); | ||
| 12 | dw.strtab.appendSliceAssumeCapacity(di.debug_str); | ||
| 13 | try dw.parseAbbrevTables(allocator, di); | ||
| 14 | try dw.parseCompileUnits(allocator, di); | ||
| 13 | } | 15 | } |
| 14 | 16 | ||
| 15 | pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void { | 17 | pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void { |
| ... | @@ -18,18 +20,27 @@ pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void { | ... | @@ -18,18 +20,27 @@ pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void { |
| 18 | cu.deinit(allocator); | 20 | cu.deinit(allocator); |
| 19 | } | 21 | } |
| 20 | dw.compile_units.deinit(allocator); | 22 | dw.compile_units.deinit(allocator); |
| 23 | dw.strtab.deinit(allocator); | ||
| 24 | dw.di_data.deinit(allocator); | ||
| 25 | } | ||
| 26 | |||
| 27 | fn appendDiData(dw: *DwarfInfo, allocator: Allocator, values: []const u8) error{OutOfMemory}!u32 { | ||
| 28 | const index: u32 = @intCast(dw.di_data.items.len); | ||
| 29 | try dw.di_data.ensureUnusedCapacity(allocator, values.len); | ||
| 30 | dw.di_data.appendSliceAssumeCapacity(values); | ||
| 31 | return index; | ||
| 21 | } | 32 | } |
| 22 | 33 | ||
| 23 | fn getString(dw: DwarfInfo, off: usize) [:0]const u8 { | 34 | fn getString(dw: DwarfInfo, off: usize) [:0]const u8 { |
| 24 | assert(off < dw.debug_str.len); | 35 | assert(off < dw.strtab.items.len); |
| 25 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(dw.debug_str.ptr + off)), 0); | 36 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(dw.strtab.items.ptr + off)), 0); |
| 26 | } | 37 | } |
| 27 | 38 | ||
| 28 | fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator) !void { | 39 | fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator, di: DebugInfo) !void { |
| 29 | const tracy = trace(@src()); | 40 | const tracy = trace(@src()); |
| 30 | defer tracy.end(); | 41 | defer tracy.end(); |
| 31 | 42 | ||
| 32 | const debug_abbrev = dw.debug_abbrev; | 43 | const debug_abbrev = di.debug_abbrev; |
| 33 | var stream = std.io.fixedBufferStream(debug_abbrev); | 44 | var stream = std.io.fixedBufferStream(debug_abbrev); |
| 34 | var creader = std.io.countingReader(stream.reader()); | 45 | var creader = std.io.countingReader(stream.reader()); |
| 35 | const reader = creader.reader(); | 46 | const reader = creader.reader(); |
| ... | @@ -77,11 +88,11 @@ fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator) !void { | ... | @@ -77,11 +88,11 @@ fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator) !void { |
| 77 | } | 88 | } |
| 78 | } | 89 | } |
| 79 | 90 | ||
| 80 | fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator) !void { | 91 | fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator, di: DebugInfo) !void { |
| 81 | const tracy = trace(@src()); | 92 | const tracy = trace(@src()); |
| 82 | defer tracy.end(); | 93 | defer tracy.end(); |
| 83 | 94 | ||
| 84 | const debug_info = dw.debug_info; | 95 | const debug_info = di.debug_info; |
| 85 | var stream = std.io.fixedBufferStream(debug_info); | 96 | var stream = std.io.fixedBufferStream(debug_info); |
| 86 | var creader = std.io.countingReader(stream.reader()); | 97 | var creader = std.io.countingReader(stream.reader()); |
| 87 | const reader = creader.reader(); | 98 | const reader = creader.reader(); |
| ... | @@ -107,7 +118,7 @@ fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator) !void { | ... | @@ -107,7 +118,7 @@ fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator) !void { |
| 107 | cu.header.address_size = try reader.readInt(u8, .little); | 118 | cu.header.address_size = try reader.readInt(u8, .little); |
| 108 | 119 | ||
| 109 | const table = dw.abbrev_tables.get(cu.header.debug_abbrev_offset).?; | 120 | const table = dw.abbrev_tables.get(cu.header.debug_abbrev_offset).?; |
| 110 | try dw.parseDie(allocator, cu, table, null, &creader); | 121 | try dw.parseDie(allocator, cu, table, di, null, &creader); |
| 111 | } | 122 | } |
| 112 | } | 123 | } |
| 113 | 124 | ||
| ... | @@ -116,6 +127,7 @@ fn parseDie( | ... | @@ -116,6 +127,7 @@ fn parseDie( |
| 116 | allocator: Allocator, | 127 | allocator: Allocator, |
| 117 | cu: *CompileUnit, | 128 | cu: *CompileUnit, |
| 118 | table: AbbrevTable, | 129 | table: AbbrevTable, |
| 130 | di: DebugInfo, | ||
| 119 | parent: ?u32, | 131 | parent: ?u32, |
| 120 | creader: anytype, | 132 | creader: anytype, |
| 121 | ) anyerror!void { | 133 | ) anyerror!void { |
| ... | @@ -140,19 +152,20 @@ fn parseDie( | ... | @@ -140,19 +152,20 @@ fn parseDie( |
| 140 | } | 152 | } |
| 141 | 153 | ||
| 142 | const decl = table.decls.get(code) orelse return error.MalformedDwarf; // TODO better errors | 154 | const decl = table.decls.get(code) orelse return error.MalformedDwarf; // TODO better errors |
| 143 | const data = dw.debug_info; | 155 | const data = di.debug_info; |
| 144 | try cu.diePtr(die).values.ensureTotalCapacityPrecise(allocator, decl.attrs.values().len); | 156 | try cu.diePtr(die).values.ensureTotalCapacityPrecise(allocator, decl.attrs.values().len); |
| 145 | 157 | ||
| 146 | for (decl.attrs.values()) |attr| { | 158 | for (decl.attrs.values()) |attr| { |
| 147 | const start = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow; | 159 | const start = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow; |
| 148 | try advanceByFormSize(cu, attr.form, creader); | 160 | try advanceByFormSize(cu, attr.form, creader); |
| 149 | const end = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow; | 161 | const end = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow; |
| 150 | cu.diePtr(die).values.appendAssumeCapacity(data[start..end]); | 162 | const index = try dw.appendDiData(allocator, data[start..end]); |
| 163 | cu.diePtr(die).values.appendAssumeCapacity(.{ .index = index, .len = @intCast(end - start) }); | ||
| 151 | } | 164 | } |
| 152 | 165 | ||
| 153 | if (decl.children) { | 166 | if (decl.children) { |
| 154 | // Open scope | 167 | // Open scope |
| 155 | try dw.parseDie(allocator, cu, table, die, creader); | 168 | try dw.parseDie(allocator, cu, table, di, die, creader); |
| 156 | } | 169 | } |
| 157 | } | 170 | } |
| 158 | } | 171 | } |
| ... | @@ -340,7 +353,7 @@ pub const CompileUnit = struct { | ... | @@ -340,7 +353,7 @@ pub const CompileUnit = struct { |
| 340 | 353 | ||
| 341 | pub const Die = struct { | 354 | pub const Die = struct { |
| 342 | code: Code, | 355 | code: Code, |
| 343 | values: std.ArrayListUnmanaged([]const u8) = .{}, | 356 | values: std.ArrayListUnmanaged(struct { index: u32, len: u32 }) = .{}, |
| 344 | children: std.ArrayListUnmanaged(Die.Index) = .{}, | 357 | children: std.ArrayListUnmanaged(Die.Index) = .{}, |
| 345 | 358 | ||
| 346 | pub fn deinit(die: *Die, gpa: Allocator) void { | 359 | pub fn deinit(die: *Die, gpa: Allocator) void { |
| ... | @@ -354,7 +367,7 @@ pub const Die = struct { | ... | @@ -354,7 +367,7 @@ pub const Die = struct { |
| 354 | const index = decl.attrs.getIndex(at) orelse return null; | 367 | const index = decl.attrs.getIndex(at) orelse return null; |
| 355 | const attr = decl.attrs.values()[index]; | 368 | const attr = decl.attrs.values()[index]; |
| 356 | const value = die.values.items[index]; | 369 | const value = die.values.items[index]; |
| 357 | return .{ .attr = attr, .bytes = value }; | 370 | return .{ .attr = attr, .bytes = ctx.di_data.items[value.index..][0..value.len] }; |
| 358 | } | 371 | } |
| 359 | 372 | ||
| 360 | pub const Index = u32; | 373 | pub const Index = u32; |
| ... | @@ -458,6 +471,12 @@ pub const Format = enum { | ... | @@ -458,6 +471,12 @@ pub const Format = enum { |
| 458 | dwarf64, | 471 | dwarf64, |
| 459 | }; | 472 | }; |
| 460 | 473 | ||
| 474 | const DebugInfo = struct { | ||
| 475 | debug_info: []const u8, | ||
| 476 | debug_abbrev: []const u8, | ||
| 477 | debug_str: []const u8, | ||
| 478 | }; | ||
| 479 | |||
| 461 | const assert = std.debug.assert; | 480 | const assert = std.debug.assert; |
| 462 | const dwarf = std.dwarf; | 481 | const dwarf = std.dwarf; |
| 463 | const leb = std.leb; | 482 | const leb = std.leb; |
src/link/MachO/Dylib.zig+49-50| ... | @@ -1,8 +1,6 @@ | ... | @@ -1,8 +1,6 @@ |
| 1 | path: []const u8, | 1 | path: []const u8, |
| 2 | data: []const u8, | ||
| 3 | index: File.Index, | 2 | index: File.Index, |
| 4 | 3 | ||
| 5 | header: ?macho.mach_header_64 = null, | ||
| 6 | exports: std.MultiArrayList(Export) = .{}, | 4 | exports: std.MultiArrayList(Export) = .{}, |
| 7 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 5 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 8 | id: ?Id = null, | 6 | id: ?Id = null, |
| ... | @@ -34,7 +32,6 @@ pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool { | ... | @@ -34,7 +32,6 @@ pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool { |
| 34 | } | 32 | } |
| 35 | 33 | ||
| 36 | pub fn deinit(self: *Dylib, allocator: Allocator) void { | 34 | pub fn deinit(self: *Dylib, allocator: Allocator) void { |
| 37 | allocator.free(self.data); | ||
| 38 | allocator.free(self.path); | 35 | allocator.free(self.path); |
| 39 | self.exports.deinit(allocator); | 36 | self.exports.deinit(allocator); |
| 40 | self.strtab.deinit(allocator); | 37 | self.strtab.deinit(allocator); |
| ... | @@ -44,22 +41,29 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void { | ... | @@ -44,22 +41,29 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void { |
| 44 | id.deinit(allocator); | 41 | id.deinit(allocator); |
| 45 | } | 42 | } |
| 46 | self.dependents.deinit(allocator); | 43 | self.dependents.deinit(allocator); |
| 44 | for (self.rpaths.keys()) |rpath| { | ||
| 45 | allocator.free(rpath); | ||
| 46 | } | ||
| 47 | self.rpaths.deinit(allocator); | 47 | self.rpaths.deinit(allocator); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | pub fn parse(self: *Dylib, macho_file: *MachO) !void { | 50 | pub fn parse(self: *Dylib, macho_file: *MachO, file: std.fs.File, fat_arch: ?fat.Arch) !void { |
| 51 | const tracy = trace(@src()); | 51 | const tracy = trace(@src()); |
| 52 | defer tracy.end(); | 52 | defer tracy.end(); |
| 53 | 53 | ||
| 54 | const gpa = macho_file.base.comp.gpa; | 54 | const gpa = macho_file.base.comp.gpa; |
| 55 | var stream = std.io.fixedBufferStream(self.data); | 55 | const offset = if (fat_arch) |ar| ar.offset else 0; |
| 56 | const reader = stream.reader(); | ||
| 57 | 56 | ||
| 58 | log.debug("parsing dylib from binary", .{}); | 57 | log.debug("parsing dylib from binary", .{}); |
| 59 | 58 | ||
| 60 | self.header = try reader.readStruct(macho.mach_header_64); | 59 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 60 | { | ||
| 61 | const amt = try file.preadAll(&header_buffer, offset); | ||
| 62 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; | ||
| 63 | } | ||
| 64 | const header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; | ||
| 61 | 65 | ||
| 62 | const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { | 66 | const this_cpu_arch: std.Target.Cpu.Arch = switch (header.cputype) { |
| 63 | macho.CPU_TYPE_ARM64 => .aarch64, | 67 | macho.CPU_TYPE_ARM64 => .aarch64, |
| 64 | macho.CPU_TYPE_X86_64 => .x86_64, | 68 | macho.CPU_TYPE_X86_64 => .x86_64, |
| 65 | else => |x| { | 69 | else => |x| { |
| ... | @@ -72,39 +76,60 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void { | ... | @@ -72,39 +76,60 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void { |
| 72 | return error.InvalidCpuArch; | 76 | return error.InvalidCpuArch; |
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | const lc_id = self.getLoadCommand(.ID_DYLIB) orelse { | 79 | const lc_buffer = try gpa.alloc(u8, header.sizeofcmds); |
| 76 | try macho_file.reportParseError2(self.index, "missing LC_ID_DYLIB load command", .{}); | 80 | defer gpa.free(lc_buffer); |
| 77 | return error.MalformedDylib; | 81 | { |
| 78 | }; | 82 | const amt = try file.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); |
| 79 | self.id = try Id.fromLoadCommand(gpa, lc_id.cast(macho.dylib_command).?, lc_id.getDylibPathName()); | 83 | if (amt != lc_buffer.len) return error.InputOutput; |
| 84 | } | ||
| 80 | 85 | ||
| 81 | var it = LoadCommandIterator{ | 86 | var it = LoadCommandIterator{ |
| 82 | .ncmds = self.header.?.ncmds, | 87 | .ncmds = header.ncmds, |
| 83 | .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds], | 88 | .buffer = lc_buffer, |
| 84 | }; | 89 | }; |
| 85 | while (it.next()) |cmd| switch (cmd.cmd()) { | 90 | while (it.next()) |cmd| switch (cmd.cmd()) { |
| 86 | .REEXPORT_DYLIB => if (self.header.?.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0) { | 91 | .ID_DYLIB => { |
| 92 | self.id = try Id.fromLoadCommand(gpa, cmd.cast(macho.dylib_command).?, cmd.getDylibPathName()); | ||
| 93 | }, | ||
| 94 | .REEXPORT_DYLIB => if (header.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0) { | ||
| 87 | const id = try Id.fromLoadCommand(gpa, cmd.cast(macho.dylib_command).?, cmd.getDylibPathName()); | 95 | const id = try Id.fromLoadCommand(gpa, cmd.cast(macho.dylib_command).?, cmd.getDylibPathName()); |
| 88 | try self.dependents.append(gpa, id); | 96 | try self.dependents.append(gpa, id); |
| 89 | }, | 97 | }, |
| 90 | .DYLD_INFO_ONLY => { | 98 | .DYLD_INFO_ONLY => { |
| 91 | const dyld_cmd = cmd.cast(macho.dyld_info_command).?; | 99 | const dyld_cmd = cmd.cast(macho.dyld_info_command).?; |
| 92 | const data = self.data[dyld_cmd.export_off..][0..dyld_cmd.export_size]; | 100 | const data = try gpa.alloc(u8, dyld_cmd.export_size); |
| 101 | defer gpa.free(data); | ||
| 102 | const amt = try file.preadAll(data, dyld_cmd.export_off + offset); | ||
| 103 | if (amt != data.len) return error.InputOutput; | ||
| 93 | try self.parseTrie(data, macho_file); | 104 | try self.parseTrie(data, macho_file); |
| 94 | }, | 105 | }, |
| 95 | .DYLD_EXPORTS_TRIE => { | 106 | .DYLD_EXPORTS_TRIE => { |
| 96 | const ld_cmd = cmd.cast(macho.linkedit_data_command).?; | 107 | const ld_cmd = cmd.cast(macho.linkedit_data_command).?; |
| 97 | const data = self.data[ld_cmd.dataoff..][0..ld_cmd.datasize]; | 108 | const data = try gpa.alloc(u8, ld_cmd.datasize); |
| 109 | defer gpa.free(data); | ||
| 110 | const amt = try file.preadAll(data, ld_cmd.dataoff + offset); | ||
| 111 | if (amt != data.len) return error.InputOutput; | ||
| 98 | try self.parseTrie(data, macho_file); | 112 | try self.parseTrie(data, macho_file); |
| 99 | }, | 113 | }, |
| 100 | .RPATH => { | 114 | .RPATH => { |
| 101 | const path = cmd.getRpathPathName(); | 115 | const path = cmd.getRpathPathName(); |
| 102 | try self.rpaths.put(gpa, path, {}); | 116 | try self.rpaths.put(gpa, try gpa.dupe(u8, path), {}); |
| 117 | }, | ||
| 118 | .BUILD_VERSION, | ||
| 119 | .VERSION_MIN_MACOSX, | ||
| 120 | .VERSION_MIN_IPHONEOS, | ||
| 121 | .VERSION_MIN_TVOS, | ||
| 122 | .VERSION_MIN_WATCHOS, | ||
| 123 | => { | ||
| 124 | self.platform = MachO.Platform.fromLoadCommand(cmd); | ||
| 103 | }, | 125 | }, |
| 104 | else => {}, | 126 | else => {}, |
| 105 | }; | 127 | }; |
| 106 | 128 | ||
| 107 | self.initPlatform(); | 129 | if (self.id == null) { |
| 130 | try macho_file.reportParseError2(self.index, "missing LC_ID_DYLIB load command", .{}); | ||
| 131 | return error.MalformedDylib; | ||
| 132 | } | ||
| 108 | 133 | ||
| 109 | if (self.platform) |platform| { | 134 | if (self.platform) |platform| { |
| 110 | if (!macho_file.platform.eqlTarget(platform)) { | 135 | if (!macho_file.platform.eqlTarget(platform)) { |
| ... | @@ -168,7 +193,7 @@ const TrieIterator = struct { | ... | @@ -168,7 +193,7 @@ const TrieIterator = struct { |
| 168 | 193 | ||
| 169 | pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void { | 194 | pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void { |
| 170 | try self.exports.append(allocator, .{ | 195 | try self.exports.append(allocator, .{ |
| 171 | .name = try self.insertString(allocator, name), | 196 | .name = try self.addString(allocator, name), |
| 172 | .flags = flags, | 197 | .flags = flags, |
| 173 | }); | 198 | }); |
| 174 | } | 199 | } |
| ... | @@ -479,24 +504,6 @@ pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void { | ... | @@ -479,24 +504,6 @@ pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void { |
| 479 | } | 504 | } |
| 480 | } | 505 | } |
| 481 | 506 | ||
| 482 | fn initPlatform(self: *Dylib) void { | ||
| 483 | var it = LoadCommandIterator{ | ||
| 484 | .ncmds = self.header.?.ncmds, | ||
| 485 | .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds], | ||
| 486 | }; | ||
| 487 | self.platform = while (it.next()) |cmd| { | ||
| 488 | switch (cmd.cmd()) { | ||
| 489 | .BUILD_VERSION, | ||
| 490 | .VERSION_MIN_MACOSX, | ||
| 491 | .VERSION_MIN_IPHONEOS, | ||
| 492 | .VERSION_MIN_TVOS, | ||
| 493 | .VERSION_MIN_WATCHOS, | ||
| 494 | => break MachO.Platform.fromLoadCommand(cmd), | ||
| 495 | else => {}, | ||
| 496 | } | ||
| 497 | } else null; | ||
| 498 | } | ||
| 499 | |||
| 500 | pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void { | 507 | pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void { |
| 501 | const tracy = trace(@src()); | 508 | const tracy = trace(@src()); |
| 502 | defer tracy.end(); | 509 | defer tracy.end(); |
| ... | @@ -526,8 +533,10 @@ pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void { | ... | @@ -526,8 +533,10 @@ pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void { |
| 526 | for (self.symbols.items) |sym_index| { | 533 | for (self.symbols.items) |sym_index| { |
| 527 | const sym = macho_file.getSymbol(sym_index); | 534 | const sym = macho_file.getSymbol(sym_index); |
| 528 | const name = sym.name; | 535 | const name = sym.name; |
| 536 | const global = sym.flags.global; | ||
| 529 | sym.* = .{}; | 537 | sym.* = .{}; |
| 530 | sym.name = name; | 538 | sym.name = name; |
| 539 | sym.flags.global = global; | ||
| 531 | } | 540 | } |
| 532 | } | 541 | } |
| 533 | 542 | ||
| ... | @@ -589,17 +598,7 @@ pub inline fn getUmbrella(self: Dylib, macho_file: *MachO) *Dylib { | ... | @@ -589,17 +598,7 @@ pub inline fn getUmbrella(self: Dylib, macho_file: *MachO) *Dylib { |
| 589 | return macho_file.getFile(self.umbrella).?.dylib; | 598 | return macho_file.getFile(self.umbrella).?.dylib; |
| 590 | } | 599 | } |
| 591 | 600 | ||
| 592 | fn getLoadCommand(self: Dylib, lc: macho.LC) ?LoadCommandIterator.LoadCommand { | 601 | fn addString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 { |
| 593 | var it = LoadCommandIterator{ | ||
| 594 | .ncmds = self.header.?.ncmds, | ||
| 595 | .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds], | ||
| 596 | }; | ||
| 597 | while (it.next()) |cmd| { | ||
| 598 | if (cmd.cmd() == lc) return cmd; | ||
| 599 | } else return null; | ||
| 600 | } | ||
| 601 | |||
| 602 | fn insertString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 { | ||
| 603 | const off = @as(u32, @intCast(self.strtab.items.len)); | 602 | const off = @as(u32, @intCast(self.strtab.items.len)); |
| 604 | try self.strtab.writer(allocator).print("{s}\x00", .{name}); | 603 | try self.strtab.writer(allocator).print("{s}\x00", .{name}); |
| 605 | return off; | 604 | return off; |
src/link/MachO/InternalObject.zig+38-12| ... | @@ -3,6 +3,7 @@ index: File.Index, | ... | @@ -3,6 +3,7 @@ index: File.Index, |
| 3 | sections: std.MultiArrayList(Section) = .{}, | 3 | sections: std.MultiArrayList(Section) = .{}, |
| 4 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 4 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 5 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 5 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 6 | strtab: std.ArrayListUnmanaged(u8) = .{}, | ||
| 6 | 7 | ||
| 7 | objc_methnames: std.ArrayListUnmanaged(u8) = .{}, | 8 | objc_methnames: std.ArrayListUnmanaged(u8) = .{}, |
| 8 | objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64), | 9 | objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64), |
| ... | @@ -16,6 +17,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void { | ... | @@ -16,6 +17,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void { |
| 16 | self.sections.deinit(allocator); | 17 | self.sections.deinit(allocator); |
| 17 | self.atoms.deinit(allocator); | 18 | self.atoms.deinit(allocator); |
| 18 | self.symbols.deinit(allocator); | 19 | self.symbols.deinit(allocator); |
| 20 | self.strtab.deinit(allocator); | ||
| 19 | self.objc_methnames.deinit(allocator); | 21 | self.objc_methnames.deinit(allocator); |
| 20 | } | 22 | } |
| 21 | 23 | ||
| ... | @@ -26,7 +28,11 @@ pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO) | ... | @@ -26,7 +28,11 @@ pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO) |
| 26 | const gop = try macho_file.getOrCreateGlobal(off); | 28 | const gop = try macho_file.getOrCreateGlobal(off); |
| 27 | self.symbols.addOneAssumeCapacity().* = gop.index; | 29 | self.symbols.addOneAssumeCapacity().* = gop.index; |
| 28 | const sym = macho_file.getSymbol(gop.index); | 30 | const sym = macho_file.getSymbol(gop.index); |
| 29 | sym.* = .{ .name = off, .file = self.index }; | 31 | sym.file = self.index; |
| 32 | sym.value = 0; | ||
| 33 | sym.atom = 0; | ||
| 34 | sym.nlist_idx = 0; | ||
| 35 | sym.flags = .{ .global = true }; | ||
| 30 | return gop.index; | 36 | return gop.index; |
| 31 | } | 37 | } |
| 32 | 38 | ||
| ... | @@ -45,7 +51,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil | ... | @@ -45,7 +51,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil |
| 45 | defer gpa.free(name); | 51 | defer gpa.free(name); |
| 46 | const atom = macho_file.getAtom(atom_index).?; | 52 | const atom = macho_file.getAtom(atom_index).?; |
| 47 | atom.atom_index = atom_index; | 53 | atom.atom_index = atom_index; |
| 48 | atom.name = try macho_file.strings.insert(gpa, name); | 54 | atom.name = try self.addString(gpa, name); |
| 49 | atom.file = self.index; | 55 | atom.file = self.index; |
| 50 | atom.size = methname.len + 1; | 56 | atom.size = methname.len + 1; |
| 51 | atom.alignment = .@"1"; | 57 | atom.alignment = .@"1"; |
| ... | @@ -79,7 +85,7 @@ fn addObjcSelrefsSection( | ... | @@ -79,7 +85,7 @@ fn addObjcSelrefsSection( |
| 79 | defer gpa.free(name); | 85 | defer gpa.free(name); |
| 80 | const atom = macho_file.getAtom(atom_index).?; | 86 | const atom = macho_file.getAtom(atom_index).?; |
| 81 | atom.atom_index = atom_index; | 87 | atom.atom_index = atom_index; |
| 82 | atom.name = try macho_file.strings.insert(gpa, name); | 88 | atom.name = try self.addString(gpa, name); |
| 83 | atom.file = self.index; | 89 | atom.file = self.index; |
| 84 | atom.size = @sizeOf(u64); | 90 | atom.size = @sizeOf(u64); |
| 85 | atom.alignment = .@"8"; | 91 | atom.alignment = .@"8"; |
| ... | @@ -158,16 +164,36 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8, | ... | @@ -158,16 +164,36 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8, |
| 158 | return n_sect; | 164 | return n_sect; |
| 159 | } | 165 | } |
| 160 | 166 | ||
| 161 | pub fn getSectionData(self: *const InternalObject, index: u32) []const u8 { | 167 | pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) !void { |
| 168 | assert(buffer.len == atom.size); | ||
| 162 | const slice = self.sections.slice(); | 169 | const slice = self.sections.slice(); |
| 163 | assert(index < slice.items(.header).len); | 170 | const sect = slice.items(.header)[atom.n_sect]; |
| 164 | const sect = slice.items(.header)[index]; | 171 | const extra = slice.items(.extra)[atom.n_sect]; |
| 165 | const extra = slice.items(.extra)[index]; | 172 | const data = if (extra.is_objc_methname) |
| 166 | if (extra.is_objc_methname) { | 173 | self.objc_methnames.items[sect.offset..][0..sect.size] |
| 167 | return self.objc_methnames.items[sect.offset..][0..sect.size]; | 174 | else if (extra.is_objc_selref) |
| 168 | } else if (extra.is_objc_selref) { | 175 | &self.objc_selrefs |
| 169 | return &self.objc_selrefs; | 176 | else |
| 170 | } else @panic("ref to non-existent section"); | 177 | @panic("ref to non-existent section"); |
| 178 | @memcpy(buffer, data[atom.off..][0..atom.size]); | ||
| 179 | } | ||
| 180 | |||
| 181 | pub fn getAtomRelocs(self: *const InternalObject, atom: Atom) []const Relocation { | ||
| 182 | const relocs = self.sections.items(.relocs)[atom.n_sect]; | ||
| 183 | return relocs.items[atom.relocs.pos..][0..atom.relocs.len]; | ||
| 184 | } | ||
| 185 | |||
| 186 | fn addString(self: *InternalObject, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 { | ||
| 187 | const off: u32 = @intCast(self.strtab.items.len); | ||
| 188 | try self.strtab.ensureUnusedCapacity(allocator, name.len + 1); | ||
| 189 | self.strtab.appendSliceAssumeCapacity(name); | ||
| 190 | self.strtab.appendAssumeCapacity(0); | ||
| 191 | return off; | ||
| 192 | } | ||
| 193 | |||
| 194 | pub fn getString(self: InternalObject, off: u32) [:0]const u8 { | ||
| 195 | assert(off < self.strtab.items.len); | ||
| 196 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | ||
| 171 | } | 197 | } |
| 172 | 198 | ||
| 173 | pub fn asFile(self: *InternalObject) File { | 199 | pub fn asFile(self: *InternalObject) File { |
src/link/MachO/Object.zig+178-118| ... | @@ -1,13 +1,13 @@ | ... | @@ -1,13 +1,13 @@ |
| 1 | archive: ?[]const u8 = null, | 1 | archive: ?Archive = null, |
| 2 | path: []const u8, | 2 | path: []const u8, |
| 3 | file: std.fs.File, | ||
| 3 | mtime: u64, | 4 | mtime: u64, |
| 4 | data: []const u8, | ||
| 5 | index: File.Index, | 5 | index: File.Index, |
| 6 | 6 | ||
| 7 | header: ?macho.mach_header_64 = null, | 7 | header: ?macho.mach_header_64 = null, |
| 8 | sections: std.MultiArrayList(Section) = .{}, | 8 | sections: std.MultiArrayList(Section) = .{}, |
| 9 | symtab: std.MultiArrayList(Nlist) = .{}, | 9 | symtab: std.MultiArrayList(Nlist) = .{}, |
| 10 | strtab: []const u8 = &[0]u8{}, | 10 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 11 | 11 | ||
| 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 12 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 13 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| ... | @@ -22,6 +22,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{}, | ... | @@ -22,6 +22,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{}, |
| 22 | fdes: std.ArrayListUnmanaged(Fde) = .{}, | 22 | fdes: std.ArrayListUnmanaged(Fde) = .{}, |
| 23 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, | 23 | eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, |
| 24 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, | 24 | unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, |
| 25 | data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, | ||
| 25 | 26 | ||
| 26 | alive: bool = true, | 27 | alive: bool = true, |
| 27 | hidden: bool = false, | 28 | hidden: bool = false, |
| ... | @@ -29,6 +30,11 @@ hidden: bool = false, | ... | @@ -29,6 +30,11 @@ hidden: bool = false, |
| 29 | dynamic_relocs: MachO.DynamicRelocs = .{}, | 30 | dynamic_relocs: MachO.DynamicRelocs = .{}, |
| 30 | output_symtab_ctx: MachO.SymtabCtx = .{}, | 31 | output_symtab_ctx: MachO.SymtabCtx = .{}, |
| 31 | 32 | ||
| 33 | const Archive = struct { | ||
| 34 | path: []const u8, | ||
| 35 | offset: u64, | ||
| 36 | }; | ||
| 37 | |||
| 32 | pub fn isObject(path: []const u8) !bool { | 38 | pub fn isObject(path: []const u8) !bool { |
| 33 | const file = try std.fs.cwd().openFile(path, .{}); | 39 | const file = try std.fs.cwd().openFile(path, .{}); |
| 34 | defer file.close(); | 40 | defer file.close(); |
| ... | @@ -37,12 +43,16 @@ pub fn isObject(path: []const u8) !bool { | ... | @@ -37,12 +43,16 @@ pub fn isObject(path: []const u8) !bool { |
| 37 | } | 43 | } |
| 38 | 44 | ||
| 39 | pub fn deinit(self: *Object, allocator: Allocator) void { | 45 | pub fn deinit(self: *Object, allocator: Allocator) void { |
| 46 | self.file.close(); | ||
| 47 | if (self.archive) |*ar| allocator.free(ar.path); | ||
| 48 | allocator.free(self.path); | ||
| 40 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { | 49 | for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { |
| 41 | relocs.deinit(allocator); | 50 | relocs.deinit(allocator); |
| 42 | sub.deinit(allocator); | 51 | sub.deinit(allocator); |
| 43 | } | 52 | } |
| 44 | self.sections.deinit(allocator); | 53 | self.sections.deinit(allocator); |
| 45 | self.symtab.deinit(allocator); | 54 | self.symtab.deinit(allocator); |
| 55 | self.strtab.deinit(allocator); | ||
| 46 | self.symbols.deinit(allocator); | 56 | self.symbols.deinit(allocator); |
| 47 | self.atoms.deinit(allocator); | 57 | self.atoms.deinit(allocator); |
| 48 | self.cies.deinit(allocator); | 58 | self.cies.deinit(allocator); |
| ... | @@ -54,7 +64,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { | ... | @@ -54,7 +64,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { |
| 54 | sf.stabs.deinit(allocator); | 64 | sf.stabs.deinit(allocator); |
| 55 | } | 65 | } |
| 56 | self.stab_files.deinit(allocator); | 66 | self.stab_files.deinit(allocator); |
| 57 | allocator.free(self.data); | 67 | self.data_in_code.deinit(allocator); |
| 58 | } | 68 | } |
| 59 | 69 | ||
| 60 | pub fn parse(self: *Object, macho_file: *MachO) !void { | 70 | pub fn parse(self: *Object, macho_file: *MachO) !void { |
| ... | @@ -62,10 +72,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -62,10 +72,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 62 | defer tracy.end(); | 72 | defer tracy.end(); |
| 63 | 73 | ||
| 64 | const gpa = macho_file.base.comp.gpa; | 74 | const gpa = macho_file.base.comp.gpa; |
| 65 | var stream = std.io.fixedBufferStream(self.data); | 75 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 66 | const reader = stream.reader(); | ||
| 67 | 76 | ||
| 68 | self.header = try reader.readStruct(macho.mach_header_64); | 77 | var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; |
| 78 | { | ||
| 79 | const amt = try self.file.preadAll(&header_buffer, offset); | ||
| 80 | if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; | ||
| 81 | } | ||
| 82 | self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*; | ||
| 69 | 83 | ||
| 70 | const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { | 84 | const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) { |
| 71 | macho.CPU_TYPE_ARM64 => .aarch64, | 85 | macho.CPU_TYPE_ARM64 => .aarch64, |
| ... | @@ -80,35 +94,79 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -80,35 +94,79 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 80 | return error.InvalidCpuArch; | 94 | return error.InvalidCpuArch; |
| 81 | } | 95 | } |
| 82 | 96 | ||
| 83 | if (self.getLoadCommand(.SEGMENT_64)) |lc| { | 97 | const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); |
| 84 | const sections = lc.getSections(); | 98 | defer gpa.free(lc_buffer); |
| 85 | try self.sections.ensureUnusedCapacity(gpa, sections.len); | 99 | { |
| 86 | for (sections) |sect| { | 100 | const amt = try self.file.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); |
| 87 | const index = try self.sections.addOne(gpa); | 101 | if (amt != self.header.?.sizeofcmds) return error.InputOutput; |
| 88 | self.sections.set(index, .{ .header = sect }); | ||
| 89 | |||
| 90 | if (mem.eql(u8, sect.sectName(), "__eh_frame")) { | ||
| 91 | self.eh_frame_sect_index = @intCast(index); | ||
| 92 | } else if (mem.eql(u8, sect.sectName(), "__compact_unwind")) { | ||
| 93 | self.compact_unwind_sect_index = @intCast(index); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | } | ||
| 97 | if (self.getLoadCommand(.SYMTAB)) |lc| { | ||
| 98 | const cmd = lc.cast(macho.symtab_command).?; | ||
| 99 | self.strtab = self.data[cmd.stroff..][0..cmd.strsize]; | ||
| 100 | |||
| 101 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(self.data.ptr + cmd.symoff))[0..cmd.nsyms]; | ||
| 102 | try self.symtab.ensureUnusedCapacity(gpa, symtab.len); | ||
| 103 | for (symtab) |nlist| { | ||
| 104 | self.symtab.appendAssumeCapacity(.{ | ||
| 105 | .nlist = nlist, | ||
| 106 | .atom = 0, | ||
| 107 | .size = 0, | ||
| 108 | }); | ||
| 109 | } | ||
| 110 | } | 102 | } |
| 111 | 103 | ||
| 104 | var it = LoadCommandIterator{ | ||
| 105 | .ncmds = self.header.?.ncmds, | ||
| 106 | .buffer = lc_buffer, | ||
| 107 | }; | ||
| 108 | while (it.next()) |lc| switch (lc.cmd()) { | ||
| 109 | .SEGMENT_64 => { | ||
| 110 | const sections = lc.getSections(); | ||
| 111 | try self.sections.ensureUnusedCapacity(gpa, sections.len); | ||
| 112 | for (sections) |sect| { | ||
| 113 | const index = try self.sections.addOne(gpa); | ||
| 114 | self.sections.set(index, .{ .header = sect }); | ||
| 115 | |||
| 116 | if (mem.eql(u8, sect.sectName(), "__eh_frame")) { | ||
| 117 | self.eh_frame_sect_index = @intCast(index); | ||
| 118 | } else if (mem.eql(u8, sect.sectName(), "__compact_unwind")) { | ||
| 119 | self.compact_unwind_sect_index = @intCast(index); | ||
| 120 | } | ||
| 121 | } | ||
| 122 | }, | ||
| 123 | .SYMTAB => { | ||
| 124 | const cmd = lc.cast(macho.symtab_command).?; | ||
| 125 | try self.strtab.resize(gpa, cmd.strsize); | ||
| 126 | { | ||
| 127 | const amt = try self.file.preadAll(self.strtab.items, cmd.stroff + offset); | ||
| 128 | if (amt != self.strtab.items.len) return error.InputOutput; | ||
| 129 | } | ||
| 130 | |||
| 131 | const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); | ||
| 132 | defer gpa.free(symtab_buffer); | ||
| 133 | { | ||
| 134 | const amt = try self.file.preadAll(symtab_buffer, cmd.symoff + offset); | ||
| 135 | if (amt != symtab_buffer.len) return error.InputOutput; | ||
| 136 | } | ||
| 137 | const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms]; | ||
| 138 | try self.symtab.ensureUnusedCapacity(gpa, symtab.len); | ||
| 139 | for (symtab) |nlist| { | ||
| 140 | self.symtab.appendAssumeCapacity(.{ | ||
| 141 | .nlist = nlist, | ||
| 142 | .atom = 0, | ||
| 143 | .size = 0, | ||
| 144 | }); | ||
| 145 | } | ||
| 146 | }, | ||
| 147 | .DATA_IN_CODE => { | ||
| 148 | const cmd = lc.cast(macho.linkedit_data_command).?; | ||
| 149 | const buffer = try gpa.alloc(u8, cmd.datasize); | ||
| 150 | defer gpa.free(buffer); | ||
| 151 | { | ||
| 152 | const amt = try self.file.preadAll(buffer, offset + cmd.dataoff); | ||
| 153 | if (amt != buffer.len) return error.InputOutput; | ||
| 154 | } | ||
| 155 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); | ||
| 156 | const dice = @as([*]align(1) const macho.data_in_code_entry, @ptrCast(buffer.ptr))[0..ndice]; | ||
| 157 | try self.data_in_code.appendUnalignedSlice(gpa, dice); | ||
| 158 | }, | ||
| 159 | .BUILD_VERSION, | ||
| 160 | .VERSION_MIN_MACOSX, | ||
| 161 | .VERSION_MIN_IPHONEOS, | ||
| 162 | .VERSION_MIN_TVOS, | ||
| 163 | .VERSION_MIN_WATCHOS, | ||
| 164 | => if (self.platform == null) { | ||
| 165 | self.platform = MachO.Platform.fromLoadCommand(lc); | ||
| 166 | }, | ||
| 167 | else => {}, | ||
| 168 | }; | ||
| 169 | |||
| 112 | const NlistIdx = struct { | 170 | const NlistIdx = struct { |
| 113 | nlist: macho.nlist_64, | 171 | nlist: macho.nlist_64, |
| 114 | idx: usize, | 172 | idx: usize, |
| ... | @@ -170,8 +228,6 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { | ... | @@ -170,8 +228,6 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { |
| 170 | try self.parseUnwindRecords(macho_file); | 228 | try self.parseUnwindRecords(macho_file); |
| 171 | } | 229 | } |
| 172 | 230 | ||
| 173 | self.initPlatform(); | ||
| 174 | |||
| 175 | if (self.platform) |platform| { | 231 | if (self.platform) |platform| { |
| 176 | if (!macho_file.platform.eqlTarget(platform)) { | 232 | if (!macho_file.platform.eqlTarget(platform)) { |
| 177 | try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ | 233 | try macho_file.reportParseError2(self.index, "invalid platform: {}", .{ |
| ... | @@ -237,7 +293,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -237,7 +293,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 237 | defer gpa.free(name); | 293 | defer gpa.free(name); |
| 238 | const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr; | 294 | const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr; |
| 239 | const atom_index = try self.addAtom(.{ | 295 | const atom_index = try self.addAtom(.{ |
| 240 | .name = name, | 296 | .name = try self.addString(gpa, name), |
| 241 | .n_sect = @intCast(n_sect), | 297 | .n_sect = @intCast(n_sect), |
| 242 | .off = 0, | 298 | .off = 0, |
| 243 | .size = size, | 299 | .size = size, |
| ... | @@ -267,7 +323,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -267,7 +323,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 267 | else | 323 | else |
| 268 | sect.@"align"; | 324 | sect.@"align"; |
| 269 | const atom_index = try self.addAtom(.{ | 325 | const atom_index = try self.addAtom(.{ |
| 270 | .name = self.getString(nlist.nlist.n_strx), | 326 | .name = nlist.nlist.n_strx, |
| 271 | .n_sect = @intCast(n_sect), | 327 | .n_sect = @intCast(n_sect), |
| 272 | .off = nlist.nlist.n_value - sect.addr, | 328 | .off = nlist.nlist.n_value - sect.addr, |
| 273 | .size = size, | 329 | .size = size, |
| ... | @@ -300,7 +356,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -300,7 +356,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 300 | defer gpa.free(name); | 356 | defer gpa.free(name); |
| 301 | 357 | ||
| 302 | const atom_index = try self.addAtom(.{ | 358 | const atom_index = try self.addAtom(.{ |
| 303 | .name = name, | 359 | .name = try self.addString(gpa, name), |
| 304 | .n_sect = @intCast(n_sect), | 360 | .n_sect = @intCast(n_sect), |
| 305 | .off = 0, | 361 | .off = 0, |
| 306 | .size = sect.size, | 362 | .size = sect.size, |
| ... | @@ -336,7 +392,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void { | ... | @@ -336,7 +392,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void { |
| 336 | } | 392 | } |
| 337 | 393 | ||
| 338 | const AddAtomArgs = struct { | 394 | const AddAtomArgs = struct { |
| 339 | name: [:0]const u8, | 395 | name: u32, |
| 340 | n_sect: u8, | 396 | n_sect: u8, |
| 341 | off: u64, | 397 | off: u64, |
| 342 | size: u64, | 398 | size: u64, |
| ... | @@ -349,7 +405,7 @@ fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index { | ... | @@ -349,7 +405,7 @@ fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index { |
| 349 | const atom = macho_file.getAtom(atom_index).?; | 405 | const atom = macho_file.getAtom(atom_index).?; |
| 350 | atom.file = self.index; | 406 | atom.file = self.index; |
| 351 | atom.atom_index = atom_index; | 407 | atom.atom_index = atom_index; |
| 352 | atom.name = try macho_file.strings.insert(gpa, args.name); | 408 | atom.name = args.name; |
| 353 | atom.n_sect = args.n_sect; | 409 | atom.n_sect = args.n_sect; |
| 354 | atom.size = args.size; | 410 | atom.size = args.size; |
| 355 | atom.alignment = Atom.Alignment.fromLog2Units(args.alignment); | 411 | atom.alignment = Atom.Alignment.fromLog2Units(args.alignment); |
| ... | @@ -376,7 +432,7 @@ fn initLiteralSections(self: *Object, macho_file: *MachO) !void { | ... | @@ -376,7 +432,7 @@ fn initLiteralSections(self: *Object, macho_file: *MachO) !void { |
| 376 | defer gpa.free(name); | 432 | defer gpa.free(name); |
| 377 | 433 | ||
| 378 | const atom_index = try self.addAtom(.{ | 434 | const atom_index = try self.addAtom(.{ |
| 379 | .name = name, | 435 | .name = try self.addString(gpa, name), |
| 380 | .n_sect = @intCast(n_sect), | 436 | .n_sect = @intCast(n_sect), |
| 381 | .off = 0, | 437 | .off = 0, |
| 382 | .size = sect.size, | 438 | .size = sect.size, |
| ... | @@ -475,10 +531,9 @@ fn initSymbols(self: *Object, macho_file: *MachO) !void { | ... | @@ -475,10 +531,9 @@ fn initSymbols(self: *Object, macho_file: *MachO) !void { |
| 475 | const index = try macho_file.addSymbol(); | 531 | const index = try macho_file.addSymbol(); |
| 476 | self.symbols.appendAssumeCapacity(index); | 532 | self.symbols.appendAssumeCapacity(index); |
| 477 | const symbol = macho_file.getSymbol(index); | 533 | const symbol = macho_file.getSymbol(index); |
| 478 | const name = self.getString(nlist.n_strx); | ||
| 479 | symbol.* = .{ | 534 | symbol.* = .{ |
| 480 | .value = nlist.n_value, | 535 | .value = nlist.n_value, |
| 481 | .name = try macho_file.strings.insert(gpa, name), | 536 | .name = nlist.n_strx, |
| 482 | .nlist_idx = @intCast(i), | 537 | .nlist_idx = @intCast(i), |
| 483 | .atom = 0, | 538 | .atom = 0, |
| 484 | .file = self.index, | 539 | .file = self.index, |
| ... | @@ -638,7 +693,10 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -638,7 +693,10 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 638 | const sect = slice.items(.header)[sect_id]; | 693 | const sect = slice.items(.header)[sect_id]; |
| 639 | const relocs = slice.items(.relocs)[sect_id]; | 694 | const relocs = slice.items(.relocs)[sect_id]; |
| 640 | 695 | ||
| 641 | const data = try self.getSectionData(sect_id); | 696 | // TODO: read into buffer directly |
| 697 | const data = try self.getSectionData(gpa, sect_id); | ||
| 698 | defer gpa.free(data); | ||
| 699 | |||
| 642 | try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len); | 700 | try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len); |
| 643 | self.eh_frame_data.appendSliceAssumeCapacity(data); | 701 | self.eh_frame_data.appendSliceAssumeCapacity(data); |
| 644 | 702 | ||
| ... | @@ -739,7 +797,8 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { | ... | @@ -739,7 +797,8 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { |
| 739 | }; | 797 | }; |
| 740 | 798 | ||
| 741 | const gpa = macho_file.base.comp.gpa; | 799 | const gpa = macho_file.base.comp.gpa; |
| 742 | const data = try self.getSectionData(sect_id); | 800 | const data = try self.getSectionData(gpa, sect_id); |
| 801 | defer gpa.free(data); | ||
| 743 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); | 802 | const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); |
| 744 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; | 803 | const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; |
| 745 | const sym_lookup = SymbolLookup{ .ctx = self }; | 804 | const sym_lookup = SymbolLookup{ .ctx = self }; |
| ... | @@ -934,24 +993,6 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { | ... | @@ -934,24 +993,6 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { |
| 934 | } | 993 | } |
| 935 | } | 994 | } |
| 936 | 995 | ||
| 937 | fn initPlatform(self: *Object) void { | ||
| 938 | var it = LoadCommandIterator{ | ||
| 939 | .ncmds = self.header.?.ncmds, | ||
| 940 | .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds], | ||
| 941 | }; | ||
| 942 | self.platform = while (it.next()) |cmd| { | ||
| 943 | switch (cmd.cmd()) { | ||
| 944 | .BUILD_VERSION, | ||
| 945 | .VERSION_MIN_MACOSX, | ||
| 946 | .VERSION_MIN_IPHONEOS, | ||
| 947 | .VERSION_MIN_TVOS, | ||
| 948 | .VERSION_MIN_WATCHOS, | ||
| 949 | => break MachO.Platform.fromLoadCommand(cmd), | ||
| 950 | else => {}, | ||
| 951 | } | ||
| 952 | } else null; | ||
| 953 | } | ||
| 954 | |||
| 955 | /// Currently, we only check if a compile unit for this input object file exists | 996 | /// Currently, we only check if a compile unit for this input object file exists |
| 956 | /// and record that so that we can emit symbol stabs. | 997 | /// and record that so that we can emit symbol stabs. |
| 957 | /// TODO in the future, we want parse debug info and debug line sections so that | 998 | /// TODO in the future, we want parse debug info and debug line sections so that |
| ... | @@ -975,12 +1016,20 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void { | ... | @@ -975,12 +1016,20 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void { |
| 975 | 1016 | ||
| 976 | if (debug_info_index == null or debug_abbrev_index == null) return; | 1017 | if (debug_info_index == null or debug_abbrev_index == null) return; |
| 977 | 1018 | ||
| 978 | var dwarf_info = DwarfInfo{ | 1019 | const debug_info = try self.getSectionData(gpa, @intCast(debug_info_index.?)); |
| 979 | .debug_info = try self.getSectionData(@intCast(debug_info_index.?)), | 1020 | defer gpa.free(debug_info); |
| 980 | .debug_abbrev = try self.getSectionData(@intCast(debug_abbrev_index.?)), | 1021 | const debug_abbrev = try self.getSectionData(gpa, @intCast(debug_abbrev_index.?)); |
| 981 | .debug_str = if (debug_str_index) |index| try self.getSectionData(@intCast(index)) else "", | 1022 | defer gpa.free(debug_abbrev); |
| 982 | }; | 1023 | const debug_str = if (debug_str_index) |index| try self.getSectionData(gpa, @intCast(index)) else &[0]u8{}; |
| 983 | dwarf_info.init(gpa) catch { | 1024 | defer gpa.free(debug_str); |
| 1025 | |||
| 1026 | var dwarf_info = DwarfInfo{}; | ||
| 1027 | errdefer dwarf_info.deinit(gpa); | ||
| 1028 | dwarf_info.init(gpa, .{ | ||
| 1029 | .debug_info = debug_info, | ||
| 1030 | .debug_abbrev = debug_abbrev, | ||
| 1031 | .debug_str = debug_str, | ||
| 1032 | }) catch { | ||
| 984 | try macho_file.reportParseError2(self.index, "invalid __DWARF info found", .{}); | 1033 | try macho_file.reportParseError2(self.index, "invalid __DWARF info found", .{}); |
| 985 | return error.MalformedObject; | 1034 | return error.MalformedObject; |
| 986 | }; | 1035 | }; |
| ... | @@ -1049,8 +1098,10 @@ pub fn resetGlobals(self: *Object, macho_file: *MachO) void { | ... | @@ -1049,8 +1098,10 @@ pub fn resetGlobals(self: *Object, macho_file: *MachO) void { |
| 1049 | if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue; | 1098 | if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue; |
| 1050 | const sym = macho_file.getSymbol(sym_index); | 1099 | const sym = macho_file.getSymbol(sym_index); |
| 1051 | const name = sym.name; | 1100 | const name = sym.name; |
| 1101 | const global = sym.flags.global; | ||
| 1052 | sym.* = .{}; | 1102 | sym.* = .{}; |
| 1053 | sym.name = name; | 1103 | sym.name = name; |
| 1104 | sym.flags.global = global; | ||
| 1054 | } | 1105 | } |
| 1055 | } | 1106 | } |
| 1056 | 1107 | ||
| ... | @@ -1137,7 +1188,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { | ... | @@ -1137,7 +1188,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { |
| 1137 | defer gpa.free(name); | 1188 | defer gpa.free(name); |
| 1138 | const atom = macho_file.getAtom(atom_index).?; | 1189 | const atom = macho_file.getAtom(atom_index).?; |
| 1139 | atom.atom_index = atom_index; | 1190 | atom.atom_index = atom_index; |
| 1140 | atom.name = try macho_file.strings.insert(gpa, name); | 1191 | atom.name = try self.addString(gpa, name); |
| 1141 | atom.file = self.index; | 1192 | atom.file = self.index; |
| 1142 | atom.size = nlist.n_value; | 1193 | atom.size = nlist.n_value; |
| 1143 | atom.alignment = Atom.Alignment.fromLog2Units((nlist.n_desc >> 8) & 0x0f); | 1194 | atom.alignment = Atom.Alignment.fromLog2Units((nlist.n_desc >> 8) & 0x0f); |
| ... | @@ -1151,6 +1202,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { | ... | @@ -1151,6 +1202,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void { |
| 1151 | 1202 | ||
| 1152 | sym.value = 0; | 1203 | sym.value = 0; |
| 1153 | sym.atom = atom_index; | 1204 | sym.atom = atom_index; |
| 1205 | sym.flags.global = true; | ||
| 1154 | sym.flags.weak = false; | 1206 | sym.flags.weak = false; |
| 1155 | sym.flags.weak_ref = false; | 1207 | sym.flags.weak_ref = false; |
| 1156 | sym.flags.tentative = false; | 1208 | sym.flags.tentative = false; |
| ... | @@ -1219,8 +1271,8 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { | ... | @@ -1219,8 +1271,8 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { |
| 1219 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir | 1271 | self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir |
| 1220 | self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name | 1272 | self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name |
| 1221 | 1273 | ||
| 1222 | if (self.archive) |path| { | 1274 | if (self.archive) |ar| { |
| 1223 | self.output_symtab_ctx.strsize += @as(u32, @intCast(path.len + 1 + self.path.len + 1 + 1)); | 1275 | self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); |
| 1224 | } else { | 1276 | } else { |
| 1225 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); | 1277 | self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1)); |
| 1226 | } | 1278 | } |
| ... | @@ -1365,8 +1417,8 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void | ... | @@ -1365,8 +1417,8 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void |
| 1365 | index += 1; | 1417 | index += 1; |
| 1366 | // N_OSO path | 1418 | // N_OSO path |
| 1367 | n_strx = @as(u32, @intCast(macho_file.strtab.items.len)); | 1419 | n_strx = @as(u32, @intCast(macho_file.strtab.items.len)); |
| 1368 | if (self.archive) |path| { | 1420 | if (self.archive) |ar| { |
| 1369 | macho_file.strtab.appendSliceAssumeCapacity(path); | 1421 | macho_file.strtab.appendSliceAssumeCapacity(ar.path); |
| 1370 | macho_file.strtab.appendAssumeCapacity('('); | 1422 | macho_file.strtab.appendAssumeCapacity('('); |
| 1371 | macho_file.strtab.appendSliceAssumeCapacity(self.path); | 1423 | macho_file.strtab.appendSliceAssumeCapacity(self.path); |
| 1372 | macho_file.strtab.appendAssumeCapacity(')'); | 1424 | macho_file.strtab.appendAssumeCapacity(')'); |
| ... | @@ -1532,30 +1584,25 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void | ... | @@ -1532,30 +1584,25 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void |
| 1532 | } | 1584 | } |
| 1533 | } | 1585 | } |
| 1534 | 1586 | ||
| 1535 | fn getLoadCommand(self: Object, lc: macho.LC) ?LoadCommandIterator.LoadCommand { | 1587 | fn getSectionData(self: *const Object, allocator: Allocator, index: u32) ![]u8 { |
| 1536 | var it = LoadCommandIterator{ | ||
| 1537 | .ncmds = self.header.?.ncmds, | ||
| 1538 | .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds], | ||
| 1539 | }; | ||
| 1540 | while (it.next()) |cmd| { | ||
| 1541 | if (cmd.cmd() == lc) return cmd; | ||
| 1542 | } else return null; | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | pub fn getSectionData(self: *const Object, index: u32) error{Overflow}![]const u8 { | ||
| 1546 | const slice = self.sections.slice(); | 1588 | const slice = self.sections.slice(); |
| 1547 | assert(index < slice.items(.header).len); | 1589 | assert(index < slice.items(.header).len); |
| 1548 | const sect = slice.items(.header)[index]; | 1590 | const sect = slice.items(.header)[index]; |
| 1549 | const off = math.cast(usize, sect.offset) orelse return error.Overflow; | 1591 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 1550 | const size = math.cast(usize, sect.size) orelse return error.Overflow; | 1592 | const buffer = try allocator.alloc(u8, sect.size); |
| 1551 | return self.data[off..][0..size]; | 1593 | errdefer allocator.free(buffer); |
| 1594 | const amt = try self.file.preadAll(buffer, sect.offset + offset); | ||
| 1595 | if (amt != buffer.len) return error.InputOutput; | ||
| 1596 | return buffer; | ||
| 1552 | } | 1597 | } |
| 1553 | 1598 | ||
| 1554 | pub fn getAtomData(self: *const Object, atom: Atom) error{Overflow}![]const u8 { | 1599 | pub fn getAtomData(self: *const Object, atom: Atom, buffer: []u8) !void { |
| 1555 | const data = try self.getSectionData(atom.n_sect); | 1600 | assert(buffer.len == atom.size); |
| 1556 | const off = math.cast(usize, atom.off) orelse return error.Overflow; | 1601 | const slice = self.sections.slice(); |
| 1557 | const size = math.cast(usize, atom.size) orelse return error.Overflow; | 1602 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 1558 | return data[off..][0..size]; | 1603 | const sect = slice.items(.header)[atom.n_sect]; |
| 1604 | const amt = try self.file.preadAll(buffer, sect.offset + offset + atom.off); | ||
| 1605 | if (amt != buffer.len) return error.InputOutput; | ||
| 1559 | } | 1606 | } |
| 1560 | 1607 | ||
| 1561 | pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation { | 1608 | pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation { |
| ... | @@ -1563,9 +1610,17 @@ pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation { | ... | @@ -1563,9 +1610,17 @@ pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation { |
| 1563 | return relocs.items[atom.relocs.pos..][0..atom.relocs.len]; | 1610 | return relocs.items[atom.relocs.pos..][0..atom.relocs.len]; |
| 1564 | } | 1611 | } |
| 1565 | 1612 | ||
| 1566 | fn getString(self: Object, off: u32) [:0]const u8 { | 1613 | fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 { |
| 1567 | assert(off < self.strtab.len); | 1614 | const off: u32 = @intCast(self.strtab.items.len); |
| 1568 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0); | 1615 | try self.strtab.ensureUnusedCapacity(allocator, name.len + 1); |
| 1616 | self.strtab.appendSliceAssumeCapacity(name); | ||
| 1617 | self.strtab.appendAssumeCapacity(0); | ||
| 1618 | return off; | ||
| 1619 | } | ||
| 1620 | |||
| 1621 | pub fn getString(self: Object, off: u32) [:0]const u8 { | ||
| 1622 | assert(off < self.strtab.items.len); | ||
| 1623 | return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0); | ||
| 1569 | } | 1624 | } |
| 1570 | 1625 | ||
| 1571 | pub fn hasUnwindRecords(self: Object) bool { | 1626 | pub fn hasUnwindRecords(self: Object) bool { |
| ... | @@ -1600,15 +1655,8 @@ pub fn hasObjc(self: Object) bool { | ... | @@ -1600,15 +1655,8 @@ pub fn hasObjc(self: Object) bool { |
| 1600 | return false; | 1655 | return false; |
| 1601 | } | 1656 | } |
| 1602 | 1657 | ||
| 1603 | pub fn getDataInCode(self: Object) []align(1) const macho.data_in_code_entry { | 1658 | pub fn getDataInCode(self: Object) []const macho.data_in_code_entry { |
| 1604 | const lc = self.getLoadCommand(.DATA_IN_CODE) orelse return &[0]macho.data_in_code_entry{}; | 1659 | return self.data_in_code.items; |
| 1605 | const cmd = lc.cast(macho.linkedit_data_command).?; | ||
| 1606 | const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); | ||
| 1607 | const dice = @as( | ||
| 1608 | [*]align(1) const macho.data_in_code_entry, | ||
| 1609 | @ptrCast(self.data.ptr + cmd.dataoff), | ||
| 1610 | )[0..ndice]; | ||
| 1611 | return dice; | ||
| 1612 | } | 1660 | } |
| 1613 | 1661 | ||
| 1614 | pub inline fn hasSubsections(self: Object) bool { | 1662 | pub inline fn hasSubsections(self: Object) bool { |
| ... | @@ -1762,8 +1810,8 @@ fn formatPath( | ... | @@ -1762,8 +1810,8 @@ fn formatPath( |
| 1762 | ) !void { | 1810 | ) !void { |
| 1763 | _ = unused_fmt_string; | 1811 | _ = unused_fmt_string; |
| 1764 | _ = options; | 1812 | _ = options; |
| 1765 | if (object.archive) |path| { | 1813 | if (object.archive) |ar| { |
| 1766 | try writer.writeAll(path); | 1814 | try writer.writeAll(ar.path); |
| 1767 | try writer.writeByte('('); | 1815 | try writer.writeByte('('); |
| 1768 | try writer.writeAll(object.path); | 1816 | try writer.writeAll(object.path); |
| 1769 | try writer.writeByte(')'); | 1817 | try writer.writeByte(')'); |
| ... | @@ -1831,11 +1879,17 @@ const x86_64 = struct { | ... | @@ -1831,11 +1879,17 @@ const x86_64 = struct { |
| 1831 | ) !void { | 1879 | ) !void { |
| 1832 | const gpa = macho_file.base.comp.gpa; | 1880 | const gpa = macho_file.base.comp.gpa; |
| 1833 | 1881 | ||
| 1834 | const relocs = @as( | 1882 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 1835 | [*]align(1) const macho.relocation_info, | 1883 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 1836 | @ptrCast(self.data.ptr + sect.reloff), | 1884 | defer gpa.free(relocs_buffer); |
| 1837 | )[0..sect.nreloc]; | 1885 | { |
| 1838 | const code = try self.getSectionData(@intCast(n_sect)); | 1886 | const amt = try self.file.preadAll(relocs_buffer, sect.reloff + offset); |
| 1887 | if (amt != relocs_buffer.len) return error.InputOutput; | ||
| 1888 | } | ||
| 1889 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; | ||
| 1890 | |||
| 1891 | const code = try self.getSectionData(gpa, @intCast(n_sect)); | ||
| 1892 | defer gpa.free(code); | ||
| 1839 | 1893 | ||
| 1840 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); | 1894 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| 1841 | 1895 | ||
| ... | @@ -1987,11 +2041,17 @@ const aarch64 = struct { | ... | @@ -1987,11 +2041,17 @@ const aarch64 = struct { |
| 1987 | ) !void { | 2041 | ) !void { |
| 1988 | const gpa = macho_file.base.comp.gpa; | 2042 | const gpa = macho_file.base.comp.gpa; |
| 1989 | 2043 | ||
| 1990 | const relocs = @as( | 2044 | const offset = if (self.archive) |ar| ar.offset else 0; |
| 1991 | [*]align(1) const macho.relocation_info, | 2045 | const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); |
| 1992 | @ptrCast(self.data.ptr + sect.reloff), | 2046 | defer gpa.free(relocs_buffer); |
| 1993 | )[0..sect.nreloc]; | 2047 | { |
| 1994 | const code = try self.getSectionData(@intCast(n_sect)); | 2048 | const amt = try self.file.preadAll(relocs_buffer, sect.reloff + offset); |
| 2049 | if (amt != relocs_buffer.len) return error.InputOutput; | ||
| 2050 | } | ||
| 2051 | const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; | ||
| 2052 | |||
| 2053 | const code = try self.getSectionData(gpa, @intCast(n_sect)); | ||
| 2054 | defer gpa.free(code); | ||
| 1995 | 2055 | ||
| 1996 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); | 2056 | try out.ensureTotalCapacityPrecise(gpa, relocs.len); |
| 1997 | 2057 |
src/link/MachO/Symbol.zig+11-1| ... | @@ -55,7 +55,12 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { | ... | @@ -55,7 +55,12 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool { |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 { | 57 | pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 { |
| 58 | return macho_file.strings.getAssumeExists(symbol.name); | 58 | if (symbol.flags.global) return macho_file.strings.getAssumeExists(symbol.name); |
| 59 | return switch (symbol.getFile(macho_file).?) { | ||
| 60 | .dylib => unreachable, // There are no local symbols for dylibs | ||
| 61 | .zig_object => |x| x.strtab.getAssumeExists(symbol.name), | ||
| 62 | inline else => |x| x.getString(symbol.name), | ||
| 63 | }; | ||
| 59 | } | 64 | } |
| 60 | 65 | ||
| 61 | pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom { | 66 | pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom { |
| ... | @@ -341,6 +346,11 @@ pub const Flags = packed struct { | ... | @@ -341,6 +346,11 @@ pub const Flags = packed struct { |
| 341 | /// Whether the symbol is exported at runtime. | 346 | /// Whether the symbol is exported at runtime. |
| 342 | @"export": bool = false, | 347 | @"export": bool = false, |
| 343 | 348 | ||
| 349 | /// Whether the symbol is effectively an extern and takes part in global | ||
| 350 | /// symbol resolution. Then, its name will be saved in global string interning | ||
| 351 | /// table. | ||
| 352 | global: bool = false, | ||
| 353 | |||
| 344 | /// Whether this symbol is weak. | 354 | /// Whether this symbol is weak. |
| 345 | weak: bool = false, | 355 | weak: bool = false, |
| 346 | 356 |
src/link/MachO/ZigObject.zig+21-29| ... | @@ -3,6 +3,7 @@ path: []const u8, | ... | @@ -3,6 +3,7 @@ path: []const u8, |
| 3 | index: File.Index, | 3 | index: File.Index, |
| 4 | 4 | ||
| 5 | symtab: std.MultiArrayList(Nlist) = .{}, | 5 | symtab: std.MultiArrayList(Nlist) = .{}, |
| 6 | strtab: StringTable = .{}, | ||
| 6 | 7 | ||
| 7 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 8 | symbols: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 8 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, | 9 | atoms: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| ... | @@ -52,10 +53,12 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void { | ... | @@ -52,10 +53,12 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void { |
| 52 | const gpa = comp.gpa; | 53 | const gpa = comp.gpa; |
| 53 | 54 | ||
| 54 | try self.atoms.append(gpa, 0); // null input section | 55 | try self.atoms.append(gpa, 0); // null input section |
| 56 | try self.strtab.buffer.append(gpa, 0); | ||
| 55 | } | 57 | } |
| 56 | 58 | ||
| 57 | pub fn deinit(self: *ZigObject, allocator: Allocator) void { | 59 | pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 58 | self.symtab.deinit(allocator); | 60 | self.symtab.deinit(allocator); |
| 61 | self.strtab.deinit(allocator); | ||
| 59 | self.symbols.deinit(allocator); | 62 | self.symbols.deinit(allocator); |
| 60 | self.atoms.deinit(allocator); | 63 | self.atoms.deinit(allocator); |
| 61 | self.globals_lookup.deinit(allocator); | 64 | self.globals_lookup.deinit(allocator); |
| ... | @@ -136,37 +139,24 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index { | ... | @@ -136,37 +139,24 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index { |
| 136 | return symbol_index; | 139 | return symbol_index; |
| 137 | } | 140 | } |
| 138 | 141 | ||
| 139 | /// Caller owns the memory. | 142 | pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8) !void { |
| 140 | pub fn getAtomDataAlloc( | ||
| 141 | self: ZigObject, | ||
| 142 | macho_file: *MachO, | ||
| 143 | allocator: Allocator, | ||
| 144 | atom: Atom, | ||
| 145 | ) ![]u8 { | ||
| 146 | assert(atom.file == self.index); | 143 | assert(atom.file == self.index); |
| 144 | assert(atom.size == buffer.len); | ||
| 147 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; | 145 | const sect = macho_file.sections.items(.header)[atom.out_n_sect]; |
| 148 | assert(!sect.isZerofill()); | 146 | assert(!sect.isZerofill()); |
| 149 | 147 | ||
| 150 | switch (sect.type()) { | 148 | switch (sect.type()) { |
| 151 | macho.S_THREAD_LOCAL_REGULAR => { | 149 | macho.S_THREAD_LOCAL_REGULAR => { |
| 152 | const tlv = self.tlv_initializers.get(atom.atom_index).?; | 150 | const tlv = self.tlv_initializers.get(atom.atom_index).?; |
| 153 | const data = try allocator.dupe(u8, tlv.data); | 151 | @memcpy(buffer, tlv.data); |
| 154 | return data; | ||
| 155 | }, | 152 | }, |
| 156 | macho.S_THREAD_LOCAL_VARIABLES => { | 153 | macho.S_THREAD_LOCAL_VARIABLES => { |
| 157 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | 154 | @memset(buffer, 0); |
| 158 | const data = try allocator.alloc(u8, size); | ||
| 159 | @memset(data, 0); | ||
| 160 | return data; | ||
| 161 | }, | 155 | }, |
| 162 | else => { | 156 | else => { |
| 163 | const file_offset = sect.offset + atom.value - sect.addr; | 157 | const file_offset = sect.offset + atom.value - sect.addr; |
| 164 | const size = std.math.cast(usize, atom.size) orelse return error.Overflow; | 158 | const amt = try macho_file.base.file.?.preadAll(buffer, file_offset); |
| 165 | const data = try allocator.alloc(u8, size); | 159 | if (amt != buffer.len) return error.InputOutput; |
| 166 | errdefer allocator.free(data); | ||
| 167 | const amt = try macho_file.base.file.?.preadAll(data, file_offset); | ||
| 168 | if (amt != data.len) return error.InputOutput; | ||
| 169 | return data; | ||
| 170 | }, | 160 | }, |
| 171 | } | 161 | } |
| 172 | } | 162 | } |
| ... | @@ -242,8 +232,10 @@ pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void { | ... | @@ -242,8 +232,10 @@ pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void { |
| 242 | if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue; | 232 | if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue; |
| 243 | const sym = macho_file.getSymbol(sym_index); | 233 | const sym = macho_file.getSymbol(sym_index); |
| 244 | const name = sym.name; | 234 | const name = sym.name; |
| 235 | const global = sym.flags.global; | ||
| 245 | sym.* = .{}; | 236 | sym.* = .{}; |
| 246 | sym.name = name; | 237 | sym.name = name; |
| 238 | sym.flags.global = global; | ||
| 247 | } | 239 | } |
| 248 | } | 240 | } |
| 249 | 241 | ||
| ... | @@ -686,7 +678,7 @@ fn updateDeclCode( | ... | @@ -686,7 +678,7 @@ fn updateDeclCode( |
| 686 | sym.out_n_sect = sect_index; | 678 | sym.out_n_sect = sect_index; |
| 687 | atom.out_n_sect = sect_index; | 679 | atom.out_n_sect = sect_index; |
| 688 | 680 | ||
| 689 | sym.name = try macho_file.strings.insert(gpa, decl_name); | 681 | sym.name = try self.strtab.insert(gpa, decl_name); |
| 690 | atom.flags.alive = true; | 682 | atom.flags.alive = true; |
| 691 | atom.name = sym.name; | 683 | atom.name = sym.name; |
| 692 | nlist.n_strx = sym.name; | 684 | nlist.n_strx = sym.name; |
| ... | @@ -796,7 +788,7 @@ fn createTlvInitializer( | ... | @@ -796,7 +788,7 @@ fn createTlvInitializer( |
| 796 | atom.out_n_sect = sect_index; | 788 | atom.out_n_sect = sect_index; |
| 797 | 789 | ||
| 798 | sym.value = 0; | 790 | sym.value = 0; |
| 799 | sym.name = try macho_file.strings.insert(gpa, sym_name); | 791 | sym.name = try self.strtab.insert(gpa, sym_name); |
| 800 | atom.flags.alive = true; | 792 | atom.flags.alive = true; |
| 801 | atom.name = sym.name; | 793 | atom.name = sym.name; |
| 802 | nlist.n_strx = sym.name; | 794 | nlist.n_strx = sym.name; |
| ... | @@ -849,7 +841,7 @@ fn createTlvDescriptor( | ... | @@ -849,7 +841,7 @@ fn createTlvDescriptor( |
| 849 | atom.out_n_sect = sect_index; | 841 | atom.out_n_sect = sect_index; |
| 850 | 842 | ||
| 851 | sym.value = 0; | 843 | sym.value = 0; |
| 852 | sym.name = try macho_file.strings.insert(gpa, name); | 844 | sym.name = try self.strtab.insert(gpa, name); |
| 853 | atom.flags.alive = true; | 845 | atom.flags.alive = true; |
| 854 | atom.name = sym.name; | 846 | atom.name = sym.name; |
| 855 | nlist.n_strx = sym.name; | 847 | nlist.n_strx = sym.name; |
| ... | @@ -1019,7 +1011,7 @@ fn lowerConst( | ... | @@ -1019,7 +1011,7 @@ fn lowerConst( |
| 1019 | }; | 1011 | }; |
| 1020 | 1012 | ||
| 1021 | const sym = macho_file.getSymbol(sym_index); | 1013 | const sym = macho_file.getSymbol(sym_index); |
| 1022 | const name_str_index = try macho_file.strings.insert(gpa, name); | 1014 | const name_str_index = try self.strtab.insert(gpa, name); |
| 1023 | sym.name = name_str_index; | 1015 | sym.name = name_str_index; |
| 1024 | sym.out_n_sect = output_section_index; | 1016 | sym.out_n_sect = output_section_index; |
| 1025 | 1017 | ||
| ... | @@ -1110,7 +1102,7 @@ pub fn updateExports( | ... | @@ -1110,7 +1102,7 @@ pub fn updateExports( |
| 1110 | } | 1102 | } |
| 1111 | 1103 | ||
| 1112 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); | 1104 | const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); |
| 1113 | const global_nlist_index = if (metadata.@"export"(self, macho_file, exp_name)) |exp_index| | 1105 | const global_nlist_index = if (metadata.@"export"(self, exp_name)) |exp_index| |
| 1114 | exp_index.* | 1106 | exp_index.* |
| 1115 | else blk: { | 1107 | else blk: { |
| 1116 | const global_nlist_index = try self.getGlobalSymbol(macho_file, exp_name, null); | 1108 | const global_nlist_index = try self.getGlobalSymbol(macho_file, exp_name, null); |
| ... | @@ -1159,7 +1151,7 @@ fn updateLazySymbol( | ... | @@ -1159,7 +1151,7 @@ fn updateLazySymbol( |
| 1159 | lazy_sym.ty.fmt(mod), | 1151 | lazy_sym.ty.fmt(mod), |
| 1160 | }); | 1152 | }); |
| 1161 | defer gpa.free(name); | 1153 | defer gpa.free(name); |
| 1162 | break :blk try macho_file.strings.insert(gpa, name); | 1154 | break :blk try self.strtab.insert(gpa, name); |
| 1163 | }; | 1155 | }; |
| 1164 | 1156 | ||
| 1165 | const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| | 1157 | const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl| |
| ... | @@ -1247,7 +1239,7 @@ pub fn deleteDeclExport( | ... | @@ -1247,7 +1239,7 @@ pub fn deleteDeclExport( |
| 1247 | 1239 | ||
| 1248 | const mod = macho_file.base.comp.module.?; | 1240 | const mod = macho_file.base.comp.module.?; |
| 1249 | const exp_name = mod.intern_pool.stringToSlice(name); | 1241 | const exp_name = mod.intern_pool.stringToSlice(name); |
| 1250 | const nlist_index = metadata.@"export"(self, macho_file, exp_name) orelse return; | 1242 | const nlist_index = metadata.@"export"(self, exp_name) orelse return; |
| 1251 | 1243 | ||
| 1252 | log.debug("deleting export '{s}'", .{exp_name}); | 1244 | log.debug("deleting export '{s}'", .{exp_name}); |
| 1253 | 1245 | ||
| ... | @@ -1268,7 +1260,7 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l | ... | @@ -1268,7 +1260,7 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l |
| 1268 | const gpa = macho_file.base.comp.gpa; | 1260 | const gpa = macho_file.base.comp.gpa; |
| 1269 | const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); | 1261 | const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); |
| 1270 | defer gpa.free(sym_name); | 1262 | defer gpa.free(sym_name); |
| 1271 | const off = try macho_file.strings.insert(gpa, sym_name); | 1263 | const off = try self.strtab.insert(gpa, sym_name); |
| 1272 | const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); | 1264 | const lookup_gop = try self.globals_lookup.getOrPut(gpa, off); |
| 1273 | if (!lookup_gop.found_existing) { | 1265 | if (!lookup_gop.found_existing) { |
| 1274 | const nlist_index = try self.addNlist(gpa); | 1266 | const nlist_index = try self.addNlist(gpa); |
| ... | @@ -1406,10 +1398,10 @@ const DeclMetadata = struct { | ... | @@ -1406,10 +1398,10 @@ const DeclMetadata = struct { |
| 1406 | /// A list of all exports aliases of this Decl. | 1398 | /// A list of all exports aliases of this Decl. |
| 1407 | exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, | 1399 | exports: std.ArrayListUnmanaged(Symbol.Index) = .{}, |
| 1408 | 1400 | ||
| 1409 | fn @"export"(m: DeclMetadata, zig_object: *ZigObject, macho_file: *MachO, name: []const u8) ?*u32 { | 1401 | fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 { |
| 1410 | for (m.exports.items) |*exp| { | 1402 | for (m.exports.items) |*exp| { |
| 1411 | const nlist = zig_object.symtab.items(.nlist)[exp.*]; | 1403 | const nlist = zig_object.symtab.items(.nlist)[exp.*]; |
| 1412 | const exp_name = macho_file.strings.getAssumeExists(nlist.n_strx); | 1404 | const exp_name = zig_object.strtab.getAssumeExists(nlist.n_strx); |
| 1413 | if (mem.eql(u8, name, exp_name)) return exp; | 1405 | if (mem.eql(u8, name, exp_name)) return exp; |
| 1414 | } | 1406 | } |
| 1415 | return null; | 1407 | return null; |
src/link/MachO/relocatable.zig+1-2| ... | @@ -290,8 +290,7 @@ fn writeAtoms(macho_file: *MachO) !void { | ... | @@ -290,8 +290,7 @@ fn writeAtoms(macho_file: *MachO) !void { |
| 290 | assert(atom.flags.alive); | 290 | assert(atom.flags.alive); |
| 291 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; | 291 | const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow; |
| 292 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; | 292 | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 293 | const atom_data = try atom.getFile(macho_file).object.getAtomData(atom.*); | 293 | try atom.getFile(macho_file).object.getAtomData(atom.*, code[off..][0..atom_size]); |
| 294 | @memcpy(code[off..][0..atom_size], atom_data); | ||
| 295 | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); | 294 | try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs); |
| 296 | } | 295 | } |
| 297 | 296 |