| ... | ... | @@ -4033,14 +4033,6 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void |
| 4033 | 4033 | seg.fileoff = mem.alignForwardGeneric(u64, segment.fileoff + segment.filesize, self.page_size); |
| 4034 | 4034 | } |
| 4035 | 4035 | } |
| 4036 | | // seg.vmaddr = blk: { |
| 4037 | | // const prev_segment = self.segments.items[self.linkedit_segment_cmd_index.? - 1]; |
| 4038 | | // break :blk mem.alignForwardGeneric(u64, prev_segment.vmaddr + prev_segment.vmsize, self.page_size); |
| 4039 | | // }; |
| 4040 | | // seg.fileoff = blk: { |
| 4041 | | // const prev_segment = self.segments.items[self.linkedit_segment_cmd_index.? - 1]; |
| 4042 | | // break :blk mem.alignForwardGeneric(u64, prev_segment.fileoff + prev_segment.filesize, self.page_size); |
| 4043 | | // }; |
| 4044 | 4036 | |
| 4045 | 4037 | try self.writeDyldInfoData(ncmds, lc_writer); |
| 4046 | 4038 | try self.writeSymtabs(ncmds, lc_writer); |
| ... | ... | @@ -4048,153 +4040,176 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void |
| 4048 | 4040 | seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size); |
| 4049 | 4041 | } |
| 4050 | 4042 | |
| 4051 | | fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4052 | | const tracy = trace(@src()); |
| 4053 | | defer tracy.end(); |
| 4043 | const AtomLessThanByAddressContext = struct { |
| 4044 | macho_file: *MachO, |
| 4045 | }; |
| 4046 | |
| 4047 | fn atomLessThanByAddress(ctx: AtomLessThanByAddressContext, lhs: *Atom, rhs: *Atom) bool { |
| 4048 | return lhs.getSymbol(ctx.macho_file).n_value < rhs.getSymbol(ctx.macho_file).n_value; |
| 4049 | } |
| 4054 | 4050 | |
| 4051 | fn collectRebaseData(self: *MachO, pointers: *std.ArrayList(bind.Pointer)) !void { |
| 4055 | 4052 | const gpa = self.base.allocator; |
| 4056 | 4053 | |
| 4057 | | var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa); |
| 4058 | | defer rebase_pointers.deinit(); |
| 4059 | | var bind_pointers = std.ArrayList(bind.Pointer).init(gpa); |
| 4060 | | defer bind_pointers.deinit(); |
| 4061 | | var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa); |
| 4062 | | defer lazy_bind_pointers.deinit(); |
| 4054 | var sorted_atoms_by_address = std.ArrayList(*Atom).init(gpa); |
| 4055 | defer sorted_atoms_by_address.deinit(); |
| 4056 | try sorted_atoms_by_address.ensureTotalCapacityPrecise(self.rebases.count()); |
| 4063 | 4057 | |
| 4064 | | const slice = self.sections.slice(); |
| 4065 | | for (slice.items(.last_atom)) |last_atom, sect_id| { |
| 4066 | | var atom = last_atom orelse continue; |
| 4067 | | const header = slice.items(.header)[sect_id]; |
| 4068 | | const segment_index = slice.items(.segment_index)[sect_id]; |
| 4069 | | const seg = self.getSegment(@intCast(u8, sect_id)); |
| 4058 | var it = self.rebases.keyIterator(); |
| 4059 | while (it.next()) |key_ptr| { |
| 4060 | sorted_atoms_by_address.appendAssumeCapacity(key_ptr.*); |
| 4061 | } |
| 4070 | 4062 | |
| 4071 | | if (mem.eql(u8, header.segName(), "__TEXT")) continue; // __TEXT is non-writable |
| 4063 | std.sort.sort(*Atom, sorted_atoms_by_address.items, AtomLessThanByAddressContext{ |
| 4064 | .macho_file = self, |
| 4065 | }, atomLessThanByAddress); |
| 4072 | 4066 | |
| 4073 | | log.debug("dyld info for {s},{s}", .{ header.segName(), header.sectName() }); |
| 4067 | const slice = self.sections.slice(); |
| 4068 | for (sorted_atoms_by_address.items) |atom| { |
| 4069 | log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); |
| 4074 | 4070 | |
| 4075 | | while (true) { |
| 4076 | | log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); |
| 4077 | | const sym = atom.getSymbol(self); |
| 4078 | | const base_offset = sym.n_value - seg.vmaddr; |
| 4079 | | |
| 4080 | | if (self.rebases.get(atom)) |rebases| { |
| 4081 | | for (rebases.items) |offset| { |
| 4082 | | log.debug(" | rebase at {x}", .{base_offset + offset}); |
| 4083 | | try rebase_pointers.append(.{ |
| 4084 | | .offset = base_offset + offset, |
| 4085 | | .segment_id = segment_index, |
| 4086 | | }); |
| 4087 | | } |
| 4088 | | } |
| 4071 | const sym = atom.getSymbol(self); |
| 4072 | const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; |
| 4073 | const seg = self.getSegment(sym.n_sect - 1); |
| 4089 | 4074 | |
| 4090 | | if (self.bindings.get(atom)) |bindings| { |
| 4091 | | for (bindings.items) |binding| { |
| 4092 | | const bind_sym = self.getSymbol(binding.target); |
| 4093 | | const bind_sym_name = self.getSymbolName(binding.target); |
| 4094 | | const dylib_ordinal = @divTrunc( |
| 4095 | | @bitCast(i16, bind_sym.n_desc), |
| 4096 | | macho.N_SYMBOL_RESOLVER, |
| 4097 | | ); |
| 4098 | | var flags: u4 = 0; |
| 4099 | | log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{ |
| 4100 | | binding.offset + base_offset, |
| 4101 | | bind_sym_name, |
| 4102 | | dylib_ordinal, |
| 4103 | | }); |
| 4104 | | if (bind_sym.weakRef()) { |
| 4105 | | log.debug(" | marking as weak ref ", .{}); |
| 4106 | | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4107 | | } |
| 4108 | | try bind_pointers.append(.{ |
| 4109 | | .offset = binding.offset + base_offset, |
| 4110 | | .segment_id = segment_index, |
| 4111 | | .dylib_ordinal = dylib_ordinal, |
| 4112 | | .name = bind_sym_name, |
| 4113 | | .bind_flags = flags, |
| 4114 | | }); |
| 4115 | | } |
| 4116 | | } |
| 4075 | const base_offset = sym.n_value - seg.vmaddr; |
| 4117 | 4076 | |
| 4118 | | if (self.lazy_bindings.get(atom)) |lazy_bindings| { |
| 4119 | | for (lazy_bindings.items) |binding| { |
| 4120 | | const bind_sym = self.getSymbol(binding.target); |
| 4121 | | const bind_sym_name = self.getSymbolName(binding.target); |
| 4122 | | const dylib_ordinal = @divTrunc( |
| 4123 | | @bitCast(i16, bind_sym.n_desc), |
| 4124 | | macho.N_SYMBOL_RESOLVER, |
| 4125 | | ); |
| 4126 | | var flags: u4 = 0; |
| 4127 | | log.debug(" | lazy bind at {x} import('{s}') ord({d})", .{ |
| 4128 | | binding.offset + base_offset, |
| 4129 | | bind_sym_name, |
| 4130 | | dylib_ordinal, |
| 4131 | | }); |
| 4132 | | if (bind_sym.weakRef()) { |
| 4133 | | log.debug(" | marking as weak ref ", .{}); |
| 4134 | | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4135 | | } |
| 4136 | | try lazy_bind_pointers.append(.{ |
| 4137 | | .offset = binding.offset + base_offset, |
| 4138 | | .segment_id = segment_index, |
| 4139 | | .dylib_ordinal = dylib_ordinal, |
| 4140 | | .name = bind_sym_name, |
| 4141 | | .bind_flags = flags, |
| 4142 | | }); |
| 4143 | | } |
| 4144 | | } |
| 4077 | const rebases = self.rebases.get(atom).?; |
| 4078 | try pointers.ensureUnusedCapacity(rebases.items.len); |
| 4079 | for (rebases.items) |offset| { |
| 4080 | log.debug(" | rebase at {x}", .{base_offset + offset}); |
| 4145 | 4081 | |
| 4146 | | if (atom.prev) |prev| { |
| 4147 | | atom = prev; |
| 4148 | | } else break; |
| 4082 | pointers.appendAssumeCapacity(.{ |
| 4083 | .offset = base_offset + offset, |
| 4084 | .segment_id = segment_index, |
| 4085 | }); |
| 4149 | 4086 | } |
| 4150 | 4087 | } |
| 4088 | } |
| 4151 | 4089 | |
| 4152 | | var trie: Trie = .{}; |
| 4153 | | defer trie.deinit(gpa); |
| 4090 | fn collectBindData(self: *MachO, pointers: *std.ArrayList(bind.Pointer), raw_bindings: anytype) !void { |
| 4091 | const gpa = self.base.allocator; |
| 4154 | 4092 | |
| 4155 | | { |
| 4156 | | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. |
| 4157 | | log.debug("generating export trie", .{}); |
| 4158 | | |
| 4159 | | const text_segment = self.segments.items[self.header_segment_cmd_index.?]; |
| 4160 | | const base_address = text_segment.vmaddr; |
| 4161 | | |
| 4162 | | if (self.base.options.output_mode == .Exe) { |
| 4163 | | for (&[_]SymbolWithLoc{ |
| 4164 | | try self.getEntryPoint(), |
| 4165 | | self.getGlobal("__mh_execute_header").?, |
| 4166 | | }) |global| { |
| 4167 | | const sym = self.getSymbol(global); |
| 4168 | | const sym_name = self.getSymbolName(global); |
| 4169 | | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); |
| 4170 | | try trie.put(gpa, .{ |
| 4171 | | .name = sym_name, |
| 4172 | | .vmaddr_offset = sym.n_value - base_address, |
| 4173 | | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, |
| 4174 | | }); |
| 4175 | | } |
| 4176 | | } else { |
| 4177 | | assert(self.base.options.output_mode == .Lib); |
| 4178 | | for (self.globals.items) |global| { |
| 4179 | | const sym = self.getSymbol(global); |
| 4180 | | |
| 4181 | | if (sym.undf()) continue; |
| 4182 | | if (!sym.ext()) continue; |
| 4183 | | if (sym.n_desc == N_DESC_GCED) continue; |
| 4184 | | |
| 4185 | | const sym_name = self.getSymbolName(global); |
| 4186 | | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); |
| 4187 | | try trie.put(gpa, .{ |
| 4188 | | .name = sym_name, |
| 4189 | | .vmaddr_offset = sym.n_value - base_address, |
| 4190 | | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, |
| 4191 | | }); |
| 4093 | var sorted_atoms_by_address = std.ArrayList(*Atom).init(gpa); |
| 4094 | defer sorted_atoms_by_address.deinit(); |
| 4095 | try sorted_atoms_by_address.ensureTotalCapacityPrecise(raw_bindings.count()); |
| 4096 | |
| 4097 | var it = raw_bindings.keyIterator(); |
| 4098 | while (it.next()) |key_ptr| { |
| 4099 | sorted_atoms_by_address.appendAssumeCapacity(key_ptr.*); |
| 4100 | } |
| 4101 | |
| 4102 | std.sort.sort(*Atom, sorted_atoms_by_address.items, AtomLessThanByAddressContext{ |
| 4103 | .macho_file = self, |
| 4104 | }, atomLessThanByAddress); |
| 4105 | |
| 4106 | const slice = self.sections.slice(); |
| 4107 | for (sorted_atoms_by_address.items) |atom| { |
| 4108 | log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); |
| 4109 | |
| 4110 | const sym = atom.getSymbol(self); |
| 4111 | const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; |
| 4112 | const seg = self.getSegment(sym.n_sect - 1); |
| 4113 | |
| 4114 | const base_offset = sym.n_value - seg.vmaddr; |
| 4115 | |
| 4116 | const bindings = raw_bindings.get(atom).?; |
| 4117 | try pointers.ensureUnusedCapacity(bindings.items.len); |
| 4118 | for (bindings.items) |binding| { |
| 4119 | const bind_sym = self.getSymbol(binding.target); |
| 4120 | const bind_sym_name = self.getSymbolName(binding.target); |
| 4121 | const dylib_ordinal = @divTrunc( |
| 4122 | @bitCast(i16, bind_sym.n_desc), |
| 4123 | macho.N_SYMBOL_RESOLVER, |
| 4124 | ); |
| 4125 | var flags: u4 = 0; |
| 4126 | log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{ |
| 4127 | binding.offset + base_offset, |
| 4128 | bind_sym_name, |
| 4129 | dylib_ordinal, |
| 4130 | }); |
| 4131 | if (bind_sym.weakRef()) { |
| 4132 | log.debug(" | marking as weak ref ", .{}); |
| 4133 | flags |= @truncate(u4, macho.BIND_SYMBOL_FLAGS_WEAK_IMPORT); |
| 4192 | 4134 | } |
| 4135 | pointers.appendAssumeCapacity(.{ |
| 4136 | .offset = binding.offset + base_offset, |
| 4137 | .segment_id = segment_index, |
| 4138 | .dylib_ordinal = dylib_ordinal, |
| 4139 | .name = bind_sym_name, |
| 4140 | .bind_flags = flags, |
| 4141 | }); |
| 4193 | 4142 | } |
| 4143 | } |
| 4144 | } |
| 4145 | |
| 4146 | fn collectExportData(self: *MachO, trie: *Trie) !void { |
| 4147 | const gpa = self.base.allocator; |
| 4148 | |
| 4149 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. |
| 4150 | log.debug("generating export trie", .{}); |
| 4151 | |
| 4152 | const exec_segment = self.segments.items[self.header_segment_cmd_index.?]; |
| 4153 | const base_address = exec_segment.vmaddr; |
| 4194 | 4154 | |
| 4195 | | try trie.finalize(gpa); |
| 4155 | if (self.base.options.output_mode == .Exe) { |
| 4156 | for (&[_]SymbolWithLoc{ |
| 4157 | try self.getEntryPoint(), |
| 4158 | self.getGlobal("__mh_execute_header").?, |
| 4159 | }) |global| { |
| 4160 | const sym = self.getSymbol(global); |
| 4161 | const sym_name = self.getSymbolName(global); |
| 4162 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); |
| 4163 | try trie.put(gpa, .{ |
| 4164 | .name = sym_name, |
| 4165 | .vmaddr_offset = sym.n_value - base_address, |
| 4166 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, |
| 4167 | }); |
| 4168 | } |
| 4169 | } else { |
| 4170 | assert(self.base.options.output_mode == .Lib); |
| 4171 | for (self.globals.items) |global| { |
| 4172 | const sym = self.getSymbol(global); |
| 4173 | |
| 4174 | if (sym.undf()) continue; |
| 4175 | if (!sym.ext()) continue; |
| 4176 | if (sym.n_desc == N_DESC_GCED) continue; |
| 4177 | |
| 4178 | const sym_name = self.getSymbolName(global); |
| 4179 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); |
| 4180 | try trie.put(gpa, .{ |
| 4181 | .name = sym_name, |
| 4182 | .vmaddr_offset = sym.n_value - base_address, |
| 4183 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, |
| 4184 | }); |
| 4185 | } |
| 4196 | 4186 | } |
| 4197 | 4187 | |
| 4188 | try trie.finalize(gpa); |
| 4189 | } |
| 4190 | |
| 4191 | fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void { |
| 4192 | const tracy = trace(@src()); |
| 4193 | defer tracy.end(); |
| 4194 | |
| 4195 | const gpa = self.base.allocator; |
| 4196 | |
| 4197 | var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa); |
| 4198 | defer rebase_pointers.deinit(); |
| 4199 | try self.collectRebaseData(&rebase_pointers); |
| 4200 | |
| 4201 | var bind_pointers = std.ArrayList(bind.Pointer).init(gpa); |
| 4202 | defer bind_pointers.deinit(); |
| 4203 | try self.collectBindData(&bind_pointers, self.bindings); |
| 4204 | |
| 4205 | var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa); |
| 4206 | defer lazy_bind_pointers.deinit(); |
| 4207 | try self.collectBindData(&lazy_bind_pointers, self.lazy_bindings); |
| 4208 | |
| 4209 | var trie: Trie = .{}; |
| 4210 | defer trie.deinit(gpa); |
| 4211 | try self.collectExportData(&trie); |
| 4212 | |
| 4198 | 4213 | const link_seg = self.getLinkeditSegmentPtr(); |
| 4199 | 4214 | const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64)); |
| 4200 | 4215 | assert(rebase_off == link_seg.fileoff); |