| ... | @@ -4033,14 +4033,6 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void | ... | @@ -4033,14 +4033,6 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void |
| 4033 | seg.fileoff = mem.alignForwardGeneric(u64, segment.fileoff + segment.filesize, self.page_size); | 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 | try self.writeDyldInfoData(ncmds, lc_writer); | 4037 | try self.writeDyldInfoData(ncmds, lc_writer); |
| 4046 | try self.writeSymtabs(ncmds, lc_writer); | 4038 | try self.writeSymtabs(ncmds, lc_writer); |
| ... | @@ -4048,153 +4040,176 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void | ... | @@ -4048,153 +4040,176 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void |
| 4048 | seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size); | 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 { | 4043 | const AtomLessThanByAddressContext = struct { |
| 4052 | const tracy = trace(@src()); | 4044 | macho_file: *MachO, |
| 4053 | defer tracy.end(); | 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 | const gpa = self.base.allocator; | 4052 | const gpa = self.base.allocator; |
| 4056 | | 4053 | |
| 4057 | var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa); | 4054 | var sorted_atoms_by_address = std.ArrayList(*Atom).init(gpa); |
| 4058 | defer rebase_pointers.deinit(); | 4055 | defer sorted_atoms_by_address.deinit(); |
| 4059 | var bind_pointers = std.ArrayList(bind.Pointer).init(gpa); | 4056 | try sorted_atoms_by_address.ensureTotalCapacityPrecise(self.rebases.count()); |
| 4060 | defer bind_pointers.deinit(); | | |
| 4061 | var lazy_bind_pointers = std.ArrayList(bind.Pointer).init(gpa); | | |
| 4062 | defer lazy_bind_pointers.deinit(); | | |
| 4063 | | 4057 | |
| 4064 | const slice = self.sections.slice(); | 4058 | var it = self.rebases.keyIterator(); |
| 4065 | for (slice.items(.last_atom)) |last_atom, sect_id| { | 4059 | while (it.next()) |key_ptr| { |
| 4066 | var atom = last_atom orelse continue; | 4060 | sorted_atoms_by_address.appendAssumeCapacity(key_ptr.*); |
| 4067 | const header = slice.items(.header)[sect_id]; | 4061 | } |
| 4068 | const segment_index = slice.items(.segment_index)[sect_id]; | | |
| 4069 | const seg = self.getSegment(@intCast(u8, sect_id)); | | |
| 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) { | 4071 | const sym = atom.getSymbol(self); |
| 4076 | log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); | 4072 | const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; |
| 4077 | const sym = atom.getSymbol(self); | 4073 | const seg = self.getSegment(sym.n_sect - 1); |
| 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 | } | | |
| 4089 | | 4074 | |
| 4090 | if (self.bindings.get(atom)) |bindings| { | 4075 | const base_offset = sym.n_value - seg.vmaddr; |
| 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 | } | | |
| 4117 | | 4076 | |
| 4118 | if (self.lazy_bindings.get(atom)) |lazy_bindings| { | 4077 | const rebases = self.rebases.get(atom).?; |
| 4119 | for (lazy_bindings.items) |binding| { | 4078 | try pointers.ensureUnusedCapacity(rebases.items.len); |
| 4120 | const bind_sym = self.getSymbol(binding.target); | 4079 | for (rebases.items) |offset| { |
| 4121 | const bind_sym_name = self.getSymbolName(binding.target); | 4080 | log.debug(" | rebase at {x}", .{base_offset + offset}); |
| 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 | } | | |
| 4145 | | 4081 | |
| 4146 | if (atom.prev) |prev| { | 4082 | pointers.appendAssumeCapacity(.{ |
| 4147 | atom = prev; | 4083 | .offset = base_offset + offset, |
| 4148 | } else break; | 4084 | .segment_id = segment_index, |
| | 4085 | }); |
| 4149 | } | 4086 | } |
| 4150 | } | 4087 | } |
| | 4088 | } |
| 4151 | | 4089 | |
| 4152 | var trie: Trie = .{}; | 4090 | fn collectBindData(self: *MachO, pointers: *std.ArrayList(bind.Pointer), raw_bindings: anytype) !void { |
| 4153 | defer trie.deinit(gpa); | 4091 | const gpa = self.base.allocator; |
| 4154 | | 4092 | |
| 4155 | { | 4093 | var sorted_atoms_by_address = std.ArrayList(*Atom).init(gpa); |
| 4156 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. | 4094 | defer sorted_atoms_by_address.deinit(); |
| 4157 | log.debug("generating export trie", .{}); | 4095 | try sorted_atoms_by_address.ensureTotalCapacityPrecise(raw_bindings.count()); |
| 4158 | | 4096 | |
| 4159 | const text_segment = self.segments.items[self.header_segment_cmd_index.?]; | 4097 | var it = raw_bindings.keyIterator(); |
| 4160 | const base_address = text_segment.vmaddr; | 4098 | while (it.next()) |key_ptr| { |
| 4161 | | 4099 | sorted_atoms_by_address.appendAssumeCapacity(key_ptr.*); |
| 4162 | if (self.base.options.output_mode == .Exe) { | 4100 | } |
| 4163 | for (&[_]SymbolWithLoc{ | 4101 | |
| 4164 | try self.getEntryPoint(), | 4102 | std.sort.sort(*Atom, sorted_atoms_by_address.items, AtomLessThanByAddressContext{ |
| 4165 | self.getGlobal("__mh_execute_header").?, | 4103 | .macho_file = self, |
| 4166 | }) |global| { | 4104 | }, atomLessThanByAddress); |
| 4167 | const sym = self.getSymbol(global); | 4105 | |
| 4168 | const sym_name = self.getSymbolName(global); | 4106 | const slice = self.sections.slice(); |
| 4169 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); | 4107 | for (sorted_atoms_by_address.items) |atom| { |
| 4170 | try trie.put(gpa, .{ | 4108 | log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, atom.getName(self) }); |
| 4171 | .name = sym_name, | 4109 | |
| 4172 | .vmaddr_offset = sym.n_value - base_address, | 4110 | const sym = atom.getSymbol(self); |
| 4173 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, | 4111 | const segment_index = slice.items(.segment_index)[sym.n_sect - 1]; |
| 4174 | }); | 4112 | const seg = self.getSegment(sym.n_sect - 1); |
| 4175 | } | 4113 | |
| 4176 | } else { | 4114 | const base_offset = sym.n_value - seg.vmaddr; |
| 4177 | assert(self.base.options.output_mode == .Lib); | 4115 | |
| 4178 | for (self.globals.items) |global| { | 4116 | const bindings = raw_bindings.get(atom).?; |
| 4179 | const sym = self.getSymbol(global); | 4117 | try pointers.ensureUnusedCapacity(bindings.items.len); |
| 4180 | | 4118 | for (bindings.items) |binding| { |
| 4181 | if (sym.undf()) continue; | 4119 | const bind_sym = self.getSymbol(binding.target); |
| 4182 | if (!sym.ext()) continue; | 4120 | const bind_sym_name = self.getSymbolName(binding.target); |
| 4183 | if (sym.n_desc == N_DESC_GCED) continue; | 4121 | const dylib_ordinal = @divTrunc( |
| 4184 | | 4122 | @bitCast(i16, bind_sym.n_desc), |
| 4185 | const sym_name = self.getSymbolName(global); | 4123 | macho.N_SYMBOL_RESOLVER, |
| 4186 | log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value }); | 4124 | ); |
| 4187 | try trie.put(gpa, .{ | 4125 | var flags: u4 = 0; |
| 4188 | .name = sym_name, | 4126 | log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{ |
| 4189 | .vmaddr_offset = sym.n_value - base_address, | 4127 | binding.offset + base_offset, |
| 4190 | .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR, | 4128 | bind_sym_name, |
| 4191 | }); | 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 | const link_seg = self.getLinkeditSegmentPtr(); | 4213 | const link_seg = self.getLinkeditSegmentPtr(); |
| 4199 | const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64)); | 4214 | const rebase_off = mem.alignForwardGeneric(u64, link_seg.fileoff, @alignOf(u64)); |
| 4200 | assert(rebase_off == link_seg.fileoff); | 4215 | assert(rebase_off == link_seg.fileoff); |