| author | |
| committer | |
| log | efa1c6124d167b3144c4d4b15ebf384130d35abd |
| tree | eb0c4757fa06819b748249b2fee5d598212ddf06 |
| parent | 897a554109baa3288d575cac0833e10edd1a316c |
6 files changed, 118 insertions(+), 41 deletions(-)
src/link/MachO.zig+2-2| ... | @@ -380,7 +380,7 @@ pub fn deinit(self: *MachO) void { | ... | @@ -380,7 +380,7 @@ pub fn deinit(self: *MachO) void { |
| 380 | 380 | ||
| 381 | pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { | 381 | pub fn flush(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node) link.File.FlushError!void { |
| 382 | // TODO: I think this is just a temp and can be removed once we can emit static archives | 382 | // TODO: I think this is just a temp and can be removed once we can emit static archives |
| 383 | if (self.base.isStaticLib() and build_options.have_llvm) { | 383 | if (self.base.isStaticLib() and build_options.have_llvm and self.base.comp.config.use_llvm) { |
| 384 | return self.base.linkAsArchive(arena, prog_node); | 384 | return self.base.linkAsArchive(arena, prog_node); |
| 385 | } | 385 | } |
| 386 | try self.flushModule(arena, prog_node); | 386 | try self.flushModule(arena, prog_node); |
| ... | @@ -396,7 +396,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node | ... | @@ -396,7 +396,7 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node |
| 396 | if (self.llvm_object) |llvm_object| { | 396 | if (self.llvm_object) |llvm_object| { |
| 397 | try self.base.emitLlvmObject(arena, llvm_object, prog_node); | 397 | try self.base.emitLlvmObject(arena, llvm_object, prog_node); |
| 398 | // TODO: I think this is just a temp and can be removed once we can emit static archives | 398 | // TODO: I think this is just a temp and can be removed once we can emit static archives |
| 399 | if (self.base.isStaticLib() and build_options.have_llvm) return; | 399 | if (self.base.isStaticLib() and build_options.have_llvm and self.base.comp.config.use_llvm) return; |
| 400 | } | 400 | } |
| 401 | 401 | ||
| 402 | var sub_prog_node = prog_node.start("MachO Flush", 0); | 402 | var sub_prog_node = prog_node.start("MachO Flush", 0); |
src/link/MachO/Archive.zig+30-31| ... | @@ -90,7 +90,7 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: | ... | @@ -90,7 +90,7 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: |
| 90 | 90 | ||
| 91 | pub fn writeHeader( | 91 | pub fn writeHeader( |
| 92 | object_name: []const u8, | 92 | object_name: []const u8, |
| 93 | object_size: u32, | 93 | object_size: usize, |
| 94 | format: Format, | 94 | format: Format, |
| 95 | writer: anytype, | 95 | writer: anytype, |
| 96 | ) !void { | 96 | ) !void { |
| ... | @@ -110,7 +110,7 @@ pub fn writeHeader( | ... | @@ -110,7 +110,7 @@ pub fn writeHeader( |
| 110 | } | 110 | } |
| 111 | @memcpy(&hdr.ar_fmag, ARFMAG); | 111 | @memcpy(&hdr.ar_fmag, ARFMAG); |
| 112 | 112 | ||
| 113 | const object_name_len = mem.alignForward(u32, object_name.len + 1, format.ptrWidth()); | 113 | const object_name_len = mem.alignForward(usize, object_name.len + 1, ptrWidth(format)); |
| 114 | const total_object_size = object_size + object_name_len; | 114 | const total_object_size = object_size + object_name_len; |
| 115 | 115 | ||
| 116 | { | 116 | { |
| ... | @@ -142,12 +142,12 @@ pub const SARMAG: u4 = 8; | ... | @@ -142,12 +142,12 @@ pub const SARMAG: u4 = 8; |
| 142 | /// String in ar_fmag at the end of each header. | 142 | /// String in ar_fmag at the end of each header. |
| 143 | const ARFMAG: *const [2:0]u8 = "`\n"; | 143 | const ARFMAG: *const [2:0]u8 = "`\n"; |
| 144 | 144 | ||
| 145 | const SYMDEF = "__.SYMDEF"; | 145 | pub const SYMDEF = "__.SYMDEF"; |
| 146 | const SYMDEF64 = "__.SYMDEF_64"; | 146 | pub const SYMDEF64 = "__.SYMDEF_64"; |
| 147 | const SYMDEF_SORTED = "__.SYMDEF SORTED"; | 147 | pub const SYMDEF_SORTED = "__.SYMDEF SORTED"; |
| 148 | const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED"; | 148 | pub const SYMDEF64_SORTED = "__.SYMDEF_64 SORTED"; |
| 149 | 149 | ||
| 150 | const ar_hdr = extern struct { | 150 | pub const ar_hdr = extern struct { |
| 151 | /// Member file name, sometimes / terminated. | 151 | /// Member file name, sometimes / terminated. |
| 152 | ar_name: [16]u8, | 152 | ar_name: [16]u8, |
| 153 | 153 | ||
| ... | @@ -197,7 +197,6 @@ const ar_hdr = extern struct { | ... | @@ -197,7 +197,6 @@ const ar_hdr = extern struct { |
| 197 | pub const ArSymtab = struct { | 197 | pub const ArSymtab = struct { |
| 198 | entries: std.ArrayListUnmanaged(Entry) = .{}, | 198 | entries: std.ArrayListUnmanaged(Entry) = .{}, |
| 199 | strtab: StringTable = .{}, | 199 | strtab: StringTable = .{}, |
| 200 | format: Format = .p32, | ||
| 201 | 200 | ||
| 202 | pub fn deinit(ar: *ArSymtab, allocator: Allocator) void { | 201 | pub fn deinit(ar: *ArSymtab, allocator: Allocator) void { |
| 203 | ar.entries.deinit(allocator); | 202 | ar.entries.deinit(allocator); |
| ... | @@ -208,16 +207,16 @@ pub const ArSymtab = struct { | ... | @@ -208,16 +207,16 @@ pub const ArSymtab = struct { |
| 208 | mem.sort(Entry, ar.entries.items, {}, Entry.lessThan); | 207 | mem.sort(Entry, ar.entries.items, {}, Entry.lessThan); |
| 209 | } | 208 | } |
| 210 | 209 | ||
| 211 | pub fn size(ar: ArSymtab) usize { | 210 | pub fn size(ar: ArSymtab, format: Format) usize { |
| 212 | const ptr_width = ar.format.ptrWidth(); | 211 | const ptr_width = ptrWidth(format); |
| 213 | return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width); | 212 | return ptr_width + ar.entries.items.len * 2 * ptr_width + ptr_width + mem.alignForward(usize, ar.strtab.buffer.items.len, ptr_width); |
| 214 | } | 213 | } |
| 215 | 214 | ||
| 216 | pub fn write(ar: ArSymtab, macho_file: *MachO, writer: anytype) !void { | 215 | pub fn write(ar: ArSymtab, format: Format, macho_file: *MachO, writer: anytype) !void { |
| 217 | // Header | 216 | // Header |
| 218 | try writeHeader(SYMDEF, ar.size()); | 217 | try writeHeader(SYMDEF, ar.size(format), format, writer); |
| 219 | // Symtab size | 218 | // Symtab size |
| 220 | try ar.writeInt(ar.entries.items.len * 2); | 219 | try writeInt(format, ar.entries.items.len * 2, writer); |
| 221 | // Symtab entries | 220 | // Symtab entries |
| 222 | for (ar.entries.items) |entry| { | 221 | for (ar.entries.items) |entry| { |
| 223 | const file_off = switch (macho_file.getFile(entry.file).?) { | 222 | const file_off = switch (macho_file.getFile(entry.file).?) { |
| ... | @@ -226,14 +225,14 @@ pub const ArSymtab = struct { | ... | @@ -226,14 +225,14 @@ pub const ArSymtab = struct { |
| 226 | else => unreachable, | 225 | else => unreachable, |
| 227 | }; | 226 | }; |
| 228 | // Name offset | 227 | // Name offset |
| 229 | try ar.writeInt(entry.off); | 228 | try writeInt(format, entry.off, writer); |
| 230 | // File offset | 229 | // File offset |
| 231 | try ar.writeInt(file_off); | 230 | try writeInt(format, file_off, writer); |
| 232 | } | 231 | } |
| 233 | // Strtab size | 232 | // Strtab size |
| 234 | const strtab_size = mem.alignForward(u64, ar.strtab.buffer.items.len, ar.format.ptrWidth()); | 233 | const strtab_size = mem.alignForward(u64, ar.strtab.buffer.items.len, ptrWidth(format)); |
| 235 | const padding = strtab_size - ar.strtab.buffer.items.len; | 234 | const padding = strtab_size - ar.strtab.buffer.items.len; |
| 236 | try ar.writeInt(strtab_size); | 235 | try writeInt(format, strtab_size, writer); |
| 237 | // Strtab | 236 | // Strtab |
| 238 | try writer.writeAll(ar.strtab.buffer.items); | 237 | try writer.writeAll(ar.strtab.buffer.items); |
| 239 | if (padding > 0) { | 238 | if (padding > 0) { |
| ... | @@ -241,13 +240,6 @@ pub const ArSymtab = struct { | ... | @@ -241,13 +240,6 @@ pub const ArSymtab = struct { |
| 241 | } | 240 | } |
| 242 | } | 241 | } |
| 243 | 242 | ||
| 244 | fn writeInt(ar: ArSymtab, value: u64, writer: anytype) !void { | ||
| 245 | switch (ar.format) { | ||
| 246 | .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little), | ||
| 247 | .p64 => try writer.writeInt(u64, value, .little), | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | const FormatContext = struct { | 243 | const FormatContext = struct { |
| 252 | ar: ArSymtab, | 244 | ar: ArSymtab, |
| 253 | macho_file: *MachO, | 245 | macho_file: *MachO, |
| ... | @@ -288,17 +280,24 @@ pub const ArSymtab = struct { | ... | @@ -288,17 +280,24 @@ pub const ArSymtab = struct { |
| 288 | }; | 280 | }; |
| 289 | }; | 281 | }; |
| 290 | 282 | ||
| 291 | const Format = enum { | 283 | pub const Format = enum { |
| 292 | p32, | 284 | p32, |
| 293 | p64, | 285 | p64, |
| 286 | }; | ||
| 294 | 287 | ||
| 295 | fn ptrWidth(self: Format) usize { | 288 | pub fn ptrWidth(format: Format) usize { |
| 296 | return switch (self) { | 289 | return switch (format) { |
| 297 | .p32 => @as(usize, 4), | 290 | .p32 => @as(usize, 4), |
| 298 | .p64 => 8, | 291 | .p64 => 8, |
| 299 | }; | 292 | }; |
| 293 | } | ||
| 294 | |||
| 295 | pub fn writeInt(format: Format, value: u64, writer: anytype) !void { | ||
| 296 | switch (format) { | ||
| 297 | .p32 => try writer.writeInt(u32, std.math.cast(u32, value) orelse return error.Overflow, .little), | ||
| 298 | .p64 => try writer.writeInt(u64, value, .little), | ||
| 300 | } | 299 | } |
| 301 | }; | 300 | } |
| 302 | 301 | ||
| 303 | pub const ArState = struct { | 302 | pub const ArState = struct { |
| 304 | /// File offset of the ar_hdr describing the contributing | 303 | /// File offset of the ar_hdr describing the contributing |
src/link/MachO/Object.zig+4-3| ... | @@ -1248,14 +1248,15 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { | ... | @@ -1248,14 +1248,15 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { |
| 1248 | self.output_ar_state.size = size; | 1248 | self.output_ar_state.size = size; |
| 1249 | } | 1249 | } |
| 1250 | 1250 | ||
| 1251 | pub fn writeAr(self: Object, macho_file: *MachO, writer: anytype) !void { | 1251 | pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { |
| 1252 | // Header | 1252 | // Header |
| 1253 | try Archive.writeHeader(self.path, self.output_ar_state.size, writer); | 1253 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; |
| 1254 | try Archive.writeHeader(self.path, size, ar_format, writer); | ||
| 1254 | // Data | 1255 | // Data |
| 1255 | const file = macho_file.getFileHandle(self.file_handle); | 1256 | const file = macho_file.getFileHandle(self.file_handle); |
| 1256 | // TODO try using copyRangeAll | 1257 | // TODO try using copyRangeAll |
| 1257 | const gpa = macho_file.base.comp.gpa; | 1258 | const gpa = macho_file.base.comp.gpa; |
| 1258 | const data = try file.readToEndAlloc(gpa, self.output_ar_state.size); | 1259 | const data = try file.readToEndAlloc(gpa, size); |
| 1259 | defer gpa.free(data); | 1260 | defer gpa.free(data); |
| 1260 | try writer.writeAll(data); | 1261 | try writer.writeAll(data); |
| 1261 | } | 1262 | } |
src/link/MachO/ZigObject.zig+3-2| ... | @@ -314,9 +314,10 @@ pub fn updateArSize(self: *ZigObject) void { | ... | @@ -314,9 +314,10 @@ pub fn updateArSize(self: *ZigObject) void { |
| 314 | self.output_ar_state.size = self.data.items.len; | 314 | self.output_ar_state.size = self.data.items.len; |
| 315 | } | 315 | } |
| 316 | 316 | ||
| 317 | pub fn writeAr(self: ZigObject, writer: anytype) !void { | 317 | pub fn writeAr(self: ZigObject, ar_format: Archive.Format, writer: anytype) !void { |
| 318 | // Header | 318 | // Header |
| 319 | try Archive.writeHeader(self.path, self.output_ar_state.size, writer); | 319 | const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; |
| 320 | try Archive.writeHeader(self.path, size, ar_format, writer); | ||
| 320 | // Data | 321 | // Data |
| 321 | try writer.writeAll(self.data.items); | 322 | try writer.writeAll(self.data.items); |
| 322 | } | 323 | } |
src/link/MachO/file.zig+16| ... | @@ -182,6 +182,22 @@ pub const File = union(enum) { | ... | @@ -182,6 +182,22 @@ pub const File = union(enum) { |
| 182 | }; | 182 | }; |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | pub fn updateArSize(file: File, macho_file: *MachO) !void { | ||
| 186 | return switch (file) { | ||
| 187 | .dylib, .internal => unreachable, | ||
| 188 | .zig_object => |x| x.updateArSize(), | ||
| 189 | .object => |x| x.updateArSize(macho_file), | ||
| 190 | }; | ||
| 191 | } | ||
| 192 | |||
| 193 | pub fn writeAr(file: File, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { | ||
| 194 | return switch (file) { | ||
| 195 | .dylib, .internal => unreachable, | ||
| 196 | .zig_object => |x| x.writeAr(ar_format, writer), | ||
| 197 | .object => |x| x.writeAr(ar_format, macho_file, writer), | ||
| 198 | }; | ||
| 199 | } | ||
| 200 | |||
| 185 | pub fn calcSymtabSize(file: File, macho_file: *MachO) !void { | 201 | pub fn calcSymtabSize(file: File, macho_file: *MachO) !void { |
| 186 | return switch (file) { | 202 | return switch (file) { |
| 187 | inline else => |x| x.calcSymtabSize(macho_file), | 203 | inline else => |x| x.calcSymtabSize(macho_file), |
src/link/MachO/relocatable.zig+63-3| ... | @@ -161,6 +161,9 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? | ... | @@ -161,6 +161,9 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 161 | if (macho_file.getZigObject()) |zo| files.appendAssumeCapacity(zo.index); | 161 | if (macho_file.getZigObject()) |zo| files.appendAssumeCapacity(zo.index); |
| 162 | for (macho_file.objects.items) |index| files.appendAssumeCapacity(index); | 162 | for (macho_file.objects.items) |index| files.appendAssumeCapacity(index); |
| 163 | 163 | ||
| 164 | const format: Archive.Format = .p32; | ||
| 165 | const ptr_width = Archive.ptrWidth(format); | ||
| 166 | |||
| 164 | // Update ar symtab from parsed objects | 167 | // Update ar symtab from parsed objects |
| 165 | var ar_symtab: Archive.ArSymtab = .{}; | 168 | var ar_symtab: Archive.ArSymtab = .{}; |
| 166 | defer ar_symtab.deinit(gpa); | 169 | defer ar_symtab.deinit(gpa); |
| ... | @@ -171,14 +174,71 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? | ... | @@ -171,14 +174,71 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? |
| 171 | 174 | ||
| 172 | ar_symtab.sort(); | 175 | ar_symtab.sort(); |
| 173 | 176 | ||
| 177 | // Update sizes of contributing objects | ||
| 178 | for (files.items) |index| { | ||
| 179 | try macho_file.getFile(index).?.updateArSize(macho_file); | ||
| 180 | } | ||
| 181 | |||
| 182 | // Update file offsets of contributing objects | ||
| 183 | const total_size: usize = blk: { | ||
| 184 | var pos: usize = Archive.SARMAG; | ||
| 185 | pos += @sizeOf(Archive.ar_hdr) + Archive.SYMDEF.len + 1; | ||
| 186 | pos = mem.alignForward(usize, pos, ptr_width); | ||
| 187 | pos += ar_symtab.size(format); | ||
| 188 | |||
| 189 | for (files.items) |index| { | ||
| 190 | const file = macho_file.getFile(index).?; | ||
| 191 | const state = switch (file) { | ||
| 192 | .zig_object => |x| &x.output_ar_state, | ||
| 193 | .object => |x| &x.output_ar_state, | ||
| 194 | else => unreachable, | ||
| 195 | }; | ||
| 196 | const path = switch (file) { | ||
| 197 | .zig_object => |x| x.path, | ||
| 198 | .object => |x| x.path, | ||
| 199 | else => unreachable, | ||
| 200 | }; | ||
| 201 | pos = mem.alignForward(usize, pos, ptr_width); | ||
| 202 | state.file_off = pos; | ||
| 203 | pos += @sizeOf(Archive.ar_hdr) + path.len + 1; | ||
| 204 | pos = mem.alignForward(usize, pos, ptr_width); | ||
| 205 | pos += math.cast(usize, state.size) orelse return error.Overflow; | ||
| 206 | } | ||
| 207 | |||
| 208 | break :blk pos; | ||
| 209 | }; | ||
| 210 | |||
| 174 | if (build_options.enable_logging) { | 211 | if (build_options.enable_logging) { |
| 175 | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)}); | 212 | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(macho_file)}); |
| 176 | } | 213 | } |
| 177 | 214 | ||
| 178 | var err = try macho_file.addErrorWithNotes(0); | 215 | var buffer = std.ArrayList(u8).init(gpa); |
| 179 | try err.addMsg(macho_file, "TODO implement flushStaticLib", .{}); | 216 | defer buffer.deinit(); |
| 217 | try buffer.ensureTotalCapacityPrecise(total_size); | ||
| 218 | const writer = buffer.writer(); | ||
| 219 | |||
| 220 | // Write magic | ||
| 221 | try writer.writeAll(Archive.ARMAG); | ||
| 180 | 222 | ||
| 181 | return error.FlushFailure; | 223 | // Write symtab |
| 224 | try ar_symtab.write(format, macho_file, writer); | ||
| 225 | |||
| 226 | // Write object files | ||
| 227 | for (files.items) |index| { | ||
| 228 | const aligned = mem.alignForward(usize, buffer.items.len, ptr_width); | ||
| 229 | const padding = aligned - buffer.items.len; | ||
| 230 | if (padding > 0) { | ||
| 231 | try writer.writeByteNTimes(0, padding); | ||
| 232 | } | ||
| 233 | try macho_file.getFile(index).?.writeAr(format, macho_file, writer); | ||
| 234 | } | ||
| 235 | |||
| 236 | assert(buffer.items.len == total_size); | ||
| 237 | |||
| 238 | try macho_file.base.file.?.setEndPos(total_size); | ||
| 239 | try macho_file.base.file.?.pwriteAll(buffer.items, 0); | ||
| 240 | |||
| 241 | if (comp.link_errors.items.len > 0) return error.FlushFailure; | ||
| 182 | } | 242 | } |
| 183 | 243 | ||
| 184 | fn markExports(macho_file: *MachO) void { | 244 | fn markExports(macho_file: *MachO) void { |