| ... | @@ -110,6 +110,8 @@ compatibility_version: ?std.SemanticVersion, | ... | @@ -110,6 +110,8 @@ compatibility_version: ?std.SemanticVersion, |
| 110 | entry_name: ?[]const u8, | 110 | entry_name: ?[]const u8, |
| 111 | platform: Platform, | 111 | platform: Platform, |
| 112 | sdk_version: ?std.SemanticVersion, | 112 | sdk_version: ?std.SemanticVersion, |
| | 113 | /// Rpath table |
| | 114 | rpath_table: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 113 | | 115 | |
| 114 | /// Hot-code swapping state. | 116 | /// Hot-code swapping state. |
| 115 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, | 117 | hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, |
| ... | @@ -200,6 +202,12 @@ pub fn createEmpty( | ... | @@ -200,6 +202,12 @@ pub fn createEmpty( |
| 200 | .mode = link.File.determineMode(false, output_mode, link_mode), | 202 | .mode = link.File.determineMode(false, output_mode, link_mode), |
| 201 | }); | 203 | }); |
| 202 | | 204 | |
| | 205 | // Filter rpaths |
| | 206 | try self.rpath_table.ensureUnusedCapacity(gpa, self.base.rpath_list.len); |
| | 207 | for (options.rpath_list) |rpath| { |
| | 208 | _ = self.rpath_table.putAssumeCapacity(rpath, {}); |
| | 209 | } |
| | 210 | |
| 203 | // Append null file | 211 | // Append null file |
| 204 | try self.files.append(gpa, .null); | 212 | try self.files.append(gpa, .null); |
| 205 | // Atom at index 0 is reserved as null atom | 213 | // Atom at index 0 is reserved as null atom |
| ... | @@ -317,6 +325,7 @@ pub fn deinit(self: *MachO) void { | ... | @@ -317,6 +325,7 @@ pub fn deinit(self: *MachO) void { |
| 317 | } | 325 | } |
| 318 | self.thunks.deinit(gpa); | 326 | self.thunks.deinit(gpa); |
| 319 | self.unwind_records.deinit(gpa); | 327 | self.unwind_records.deinit(gpa); |
| | 328 | self.rpath_table.deinit(gpa); |
| 320 | } | 329 | } |
| 321 | | 330 | |
| 322 | pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 331 | pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { |
| ... | @@ -378,15 +387,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -378,15 +387,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 378 | | 387 | |
| 379 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); | 388 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 380 | | 389 | |
| 381 | // rpaths | | |
| 382 | var rpath_table = std.StringArrayHashMap(void).init(gpa); | | |
| 383 | defer rpath_table.deinit(); | | |
| 384 | try rpath_table.ensureUnusedCapacity(self.base.rpath_list.len); | | |
| 385 | | | |
| 386 | for (self.base.rpath_list) |rpath| { | | |
| 387 | _ = rpath_table.putAssumeCapacity(rpath, {}); | | |
| 388 | } | | |
| 389 | | | |
| 390 | for (positionals.items) |obj| { | 390 | for (positionals.items) |obj| { |
| 391 | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { | 391 | self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) { |
| 392 | error.MalformedObject, | 392 | error.MalformedObject, |
| ... | @@ -533,6 +533,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -533,6 +533,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 533 | try self.generateUnwindInfo(); | 533 | try self.generateUnwindInfo(); |
| 534 | try self.initSegments(); | 534 | try self.initSegments(); |
| 535 | | 535 | |
| | 536 | try self.allocateSections(); |
| | 537 | self.allocateSegments(); |
| | 538 | self.allocateAtoms(); |
| | 539 | self.allocateSyntheticSymbols(); |
| | 540 | |
| 536 | state_log.debug("{}", .{self.dumpState()}); | 541 | state_log.debug("{}", .{self.dumpState()}); |
| 537 | | 542 | |
| 538 | @panic("TODO"); | 543 | @panic("TODO"); |
| ... | @@ -613,7 +618,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { | ... | @@ -613,7 +618,7 @@ fn dumpArgv(self: *MachO, comp: *Compilation) !void { |
| 613 | try argv.append(syslibroot); | 618 | try argv.append(syslibroot); |
| 614 | } | 619 | } |
| 615 | | 620 | |
| 616 | for (self.base.rpath_list) |rpath| { | 621 | for (self.rpath_table.keys()) |rpath| { |
| 617 | try argv.append("-rpath"); | 622 | try argv.append("-rpath"); |
| 618 | try argv.append(rpath); | 623 | try argv.append(rpath); |
| 619 | } | 624 | } |
| ... | @@ -2016,6 +2021,171 @@ fn initSegments(self: *MachO) !void { | ... | @@ -2016,6 +2021,171 @@ fn initSegments(self: *MachO) !void { |
| 2016 | self.linkedit_seg_index = self.getSegmentByName("__LINKEDIT").?; | 2021 | self.linkedit_seg_index = self.getSegmentByName("__LINKEDIT").?; |
| 2017 | } | 2022 | } |
| 2018 | | 2023 | |
| | 2024 | fn allocateSections(self: *MachO) !void { |
| | 2025 | const headerpad = load_commands.calcMinHeaderPadSize(self); |
| | 2026 | var vmaddr: u64 = if (self.pagezero_seg_index) |index| |
| | 2027 | self.segments.items[index].vmaddr + self.segments.items[index].vmsize |
| | 2028 | else |
| | 2029 | 0; |
| | 2030 | vmaddr += headerpad; |
| | 2031 | var fileoff = headerpad; |
| | 2032 | |
| | 2033 | const page_size = self.getPageSize(); |
| | 2034 | const slice = self.sections.slice(); |
| | 2035 | |
| | 2036 | var next_seg_id: u8 = if (self.pagezero_seg_index) |index| index + 1 else 0; |
| | 2037 | for (slice.items(.header), slice.items(.segment_id)) |*header, seg_id| { |
| | 2038 | if (seg_id != next_seg_id) { |
| | 2039 | vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| | 2040 | fileoff = mem.alignForward(u32, fileoff, page_size); |
| | 2041 | } |
| | 2042 | |
| | 2043 | const alignment = try math.powi(u32, 2, header.@"align"); |
| | 2044 | |
| | 2045 | vmaddr = mem.alignForward(u64, vmaddr, alignment); |
| | 2046 | header.addr = vmaddr; |
| | 2047 | vmaddr += header.size; |
| | 2048 | |
| | 2049 | if (!header.isZerofill()) { |
| | 2050 | fileoff = mem.alignForward(u32, fileoff, alignment); |
| | 2051 | header.offset = fileoff; |
| | 2052 | fileoff += @intCast(header.size); |
| | 2053 | } |
| | 2054 | |
| | 2055 | next_seg_id = seg_id; |
| | 2056 | } |
| | 2057 | } |
| | 2058 | |
| | 2059 | fn allocateSegments(self: *MachO) void { |
| | 2060 | const page_size = self.getPageSize(); |
| | 2061 | var vmaddr = if (self.pagezero_seg_index) |index| |
| | 2062 | self.segments.items[index].vmaddr + self.segments.items[index].vmsize |
| | 2063 | else |
| | 2064 | 0; |
| | 2065 | var fileoff: u64 = 0; |
| | 2066 | const index = if (self.pagezero_seg_index) |index| index + 1 else 0; |
| | 2067 | |
| | 2068 | const slice = self.sections.slice(); |
| | 2069 | var next_sect_id: u8 = 0; |
| | 2070 | for (self.segments.items[index..], index..) |*seg, seg_id| { |
| | 2071 | seg.vmaddr = vmaddr; |
| | 2072 | seg.fileoff = fileoff; |
| | 2073 | |
| | 2074 | for ( |
| | 2075 | slice.items(.header)[next_sect_id..], |
| | 2076 | slice.items(.segment_id)[next_sect_id..], |
| | 2077 | ) |header, sid| { |
| | 2078 | if (seg_id != sid) break; |
| | 2079 | |
| | 2080 | vmaddr = header.addr + header.size; |
| | 2081 | if (!header.isZerofill()) { |
| | 2082 | fileoff = header.offset + header.size; |
| | 2083 | } |
| | 2084 | |
| | 2085 | next_sect_id += 1; |
| | 2086 | } |
| | 2087 | |
| | 2088 | vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| | 2089 | fileoff = mem.alignForward(u64, fileoff, page_size); |
| | 2090 | |
| | 2091 | seg.vmsize = vmaddr - seg.vmaddr; |
| | 2092 | seg.filesize = fileoff - seg.fileoff; |
| | 2093 | } |
| | 2094 | } |
| | 2095 | |
| | 2096 | pub fn allocateAtoms(self: *MachO) void { |
| | 2097 | const slice = self.sections.slice(); |
| | 2098 | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { |
| | 2099 | if (atoms.items.len == 0) continue; |
| | 2100 | for (atoms.items) |atom_index| { |
| | 2101 | const atom = self.getAtom(atom_index).?; |
| | 2102 | assert(atom.flags.alive); |
| | 2103 | atom.value += header.addr; |
| | 2104 | } |
| | 2105 | } |
| | 2106 | |
| | 2107 | for (self.thunks.items) |*thunk| { |
| | 2108 | const header = self.sections.items(.header)[thunk.out_n_sect]; |
| | 2109 | thunk.value += header.addr; |
| | 2110 | } |
| | 2111 | } |
| | 2112 | |
| | 2113 | fn allocateSyntheticSymbols(self: *MachO) void { |
| | 2114 | const text_seg = self.getTextSegment(); |
| | 2115 | |
| | 2116 | if (self.mh_execute_header_index) |index| { |
| | 2117 | const global = self.getSymbol(index); |
| | 2118 | global.value = text_seg.vmaddr; |
| | 2119 | } |
| | 2120 | |
| | 2121 | if (self.data_sect_index) |idx| { |
| | 2122 | const sect = self.sections.items(.header)[idx]; |
| | 2123 | for (&[_]?Symbol.Index{ |
| | 2124 | self.dso_handle_index, |
| | 2125 | self.mh_dylib_header_index, |
| | 2126 | self.dyld_private_index, |
| | 2127 | }) |maybe_index| { |
| | 2128 | if (maybe_index) |index| { |
| | 2129 | const global = self.getSymbol(index); |
| | 2130 | global.value = sect.addr; |
| | 2131 | global.out_n_sect = idx; |
| | 2132 | } |
| | 2133 | } |
| | 2134 | } |
| | 2135 | |
| | 2136 | for (self.boundary_symbols.items) |sym_index| { |
| | 2137 | const sym = self.getSymbol(sym_index); |
| | 2138 | const name = sym.getName(self); |
| | 2139 | |
| | 2140 | sym.flags.@"export" = false; |
| | 2141 | sym.value = text_seg.vmaddr; |
| | 2142 | |
| | 2143 | if (mem.startsWith(u8, name, "segment$start$")) { |
| | 2144 | const segname = name["segment$start$".len..]; |
| | 2145 | if (self.getSegmentByName(segname)) |seg_id| { |
| | 2146 | const seg = self.segments.items[seg_id]; |
| | 2147 | sym.value = seg.vmaddr; |
| | 2148 | } |
| | 2149 | } else if (mem.startsWith(u8, name, "segment$stop$")) { |
| | 2150 | const segname = name["segment$stop$".len..]; |
| | 2151 | if (self.getSegmentByName(segname)) |seg_id| { |
| | 2152 | const seg = self.segments.items[seg_id]; |
| | 2153 | sym.value = seg.vmaddr + seg.vmsize; |
| | 2154 | } |
| | 2155 | } else if (mem.startsWith(u8, name, "section$start$")) { |
| | 2156 | const actual_name = name["section$start$".len..]; |
| | 2157 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| | 2158 | const segname = actual_name[0..sep]; |
| | 2159 | const sectname = actual_name[sep + 1 ..]; |
| | 2160 | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| | 2161 | const sect = self.sections.items(.header)[sect_id]; |
| | 2162 | sym.value = sect.addr; |
| | 2163 | sym.out_n_sect = sect_id; |
| | 2164 | } |
| | 2165 | } else if (mem.startsWith(u8, name, "section$stop$")) { |
| | 2166 | const actual_name = name["section$stop$".len..]; |
| | 2167 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| | 2168 | const segname = actual_name[0..sep]; |
| | 2169 | const sectname = actual_name[sep + 1 ..]; |
| | 2170 | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| | 2171 | const sect = self.sections.items(.header)[sect_id]; |
| | 2172 | sym.value = sect.addr + sect.size; |
| | 2173 | sym.out_n_sect = sect_id; |
| | 2174 | } |
| | 2175 | } else unreachable; |
| | 2176 | } |
| | 2177 | |
| | 2178 | if (self.objc_stubs.symbols.items.len > 0) { |
| | 2179 | const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr; |
| | 2180 | |
| | 2181 | for (self.objc_stubs.symbols.items, 0..) |sym_index, idx| { |
| | 2182 | const sym = self.getSymbol(sym_index); |
| | 2183 | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); |
| | 2184 | sym.out_n_sect = self.objc_stubs_sect_index.?; |
| | 2185 | } |
| | 2186 | } |
| | 2187 | } |
| | 2188 | |
| 2019 | fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { | 2189 | fn shrinkAtom(self: *MachO, atom_index: Atom.Index, new_block_size: u64) void { |
| 2020 | _ = self; | 2190 | _ = self; |
| 2021 | _ = atom_index; | 2191 | _ = atom_index; |
| ... | @@ -2952,8 +3122,8 @@ pub const Platform = struct { | ... | @@ -2952,8 +3122,8 @@ pub const Platform = struct { |
| 2952 | | 3122 | |
| 2953 | pub fn isBuildVersionCompatible(plat: Platform) bool { | 3123 | pub fn isBuildVersionCompatible(plat: Platform) bool { |
| 2954 | inline for (supported_platforms) |sup_plat| { | 3124 | inline for (supported_platforms) |sup_plat| { |
| 2955 | if (sup_plat[0] == plat.platform) { | 3125 | if (sup_plat[0] == plat.os_tag and sup_plat[1] == plat.abi) { |
| 2956 | return sup_plat[1] <= plat.version.value; | 3126 | return sup_plat[2] <= plat.toAppleVersion(); |
| 2957 | } | 3127 | } |
| 2958 | } | 3128 | } |
| 2959 | return false; | 3129 | return false; |