| author | |
| committer | |
| log | 5b3c4691e628cb288e6595974781ffbadb717c28 |
| tree | 14a665cc9085cc5f9c324cdf8cd85e3e96af29e2 |
| parent | 453c16d8acead9bc5ef19155474ba8af37d151cf |
3 files changed, 185 insertions(+), 126 deletions(-)
src/link/MachO/Object.zig+103-85| ... | @@ -9,13 +9,13 @@ const log = std.log.scoped(.object); | ... | @@ -9,13 +9,13 @@ const log = std.log.scoped(.object); |
| 9 | const macho = std.macho; | 9 | const macho = std.macho; |
| 10 | const mem = std.mem; | 10 | const mem = std.mem; |
| 11 | const reloc = @import("reloc.zig"); | 11 | const reloc = @import("reloc.zig"); |
| 12 | const parseName = @import("Zld.zig").parseName; | ||
| 13 | 12 | ||
| 14 | const Allocator = mem.Allocator; | 13 | const Allocator = mem.Allocator; |
| 15 | const Arch = std.Target.Cpu.Arch; | 14 | const Arch = std.Target.Cpu.Arch; |
| 16 | const Relocation = reloc.Relocation; | 15 | const Relocation = reloc.Relocation; |
| 17 | const Symbol = @import("Symbol.zig"); | 16 | const Symbol = @import("Symbol.zig"); |
| 18 | const TextBlock = @import("Zld.zig").TextBlock; | 17 | const TextBlock = Zld.TextBlock; |
| 18 | const Zld = @import("Zld.zig"); | ||
| 19 | 19 | ||
| 20 | usingnamespace @import("commands.zig"); | 20 | usingnamespace @import("commands.zig"); |
| 21 | 21 | ||
| ... | @@ -74,43 +74,6 @@ pub const Section = struct { | ... | @@ -74,43 +74,6 @@ pub const Section = struct { |
| 74 | allocator.free(relocs); | 74 | allocator.free(relocs); |
| 75 | } | 75 | } |
| 76 | } | 76 | } |
| 77 | |||
| 78 | pub fn segname(self: Section) []const u8 { | ||
| 79 | return parseName(&self.inner.segname); | ||
| 80 | } | ||
| 81 | |||
| 82 | pub fn sectname(self: Section) []const u8 { | ||
| 83 | return parseName(&self.inner.sectname); | ||
| 84 | } | ||
| 85 | |||
| 86 | pub fn flags(self: Section) u32 { | ||
| 87 | return self.inner.flags; | ||
| 88 | } | ||
| 89 | |||
| 90 | pub fn sectionType(self: Section) u8 { | ||
| 91 | return @truncate(u8, self.flags() & 0xff); | ||
| 92 | } | ||
| 93 | |||
| 94 | pub fn sectionAttrs(self: Section) u32 { | ||
| 95 | return self.flags() & 0xffffff00; | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn isCode(self: Section) bool { | ||
| 99 | const attr = self.sectionAttrs(); | ||
| 100 | return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 or attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | pub fn isDebug(self: Section) bool { | ||
| 104 | return self.sectionAttrs() & macho.S_ATTR_DEBUG != 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | pub fn dontDeadStrip(self: Section) bool { | ||
| 108 | return self.sectionAttrs() & macho.S_ATTR_NO_DEAD_STRIP != 0; | ||
| 109 | } | ||
| 110 | |||
| 111 | pub fn dontDeadStripIfReferencesLive(self: Section) bool { | ||
| 112 | return self.sectionAttrs() & macho.S_ATTR_LIVE_SUPPORT != 0; | ||
| 113 | } | ||
| 114 | }; | 77 | }; |
| 115 | 78 | ||
| 116 | const DebugInfo = struct { | 79 | const DebugInfo = struct { |
| ... | @@ -272,7 +235,6 @@ pub fn parse(self: *Object) !void { | ... | @@ -272,7 +235,6 @@ pub fn parse(self: *Object) !void { |
| 272 | try self.parseSymtab(); | 235 | try self.parseSymtab(); |
| 273 | try self.parseDataInCode(); | 236 | try self.parseDataInCode(); |
| 274 | try self.parseInitializers(); | 237 | try self.parseInitializers(); |
| 275 | try self.parseDummy(); | ||
| 276 | } | 238 | } |
| 277 | 239 | ||
| 278 | pub fn readLoadCommands(self: *Object, reader: anytype) !void { | 240 | pub fn readLoadCommands(self: *Object, reader: anytype) !void { |
| ... | @@ -288,8 +250,8 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void { | ... | @@ -288,8 +250,8 @@ pub fn readLoadCommands(self: *Object, reader: anytype) !void { |
| 288 | var seg = cmd.Segment; | 250 | var seg = cmd.Segment; |
| 289 | for (seg.sections.items) |*sect, j| { | 251 | for (seg.sections.items) |*sect, j| { |
| 290 | const index = @intCast(u16, j); | 252 | const index = @intCast(u16, j); |
| 291 | const segname = parseName(&sect.segname); | 253 | const segname = segmentName(sect.*); |
| 292 | const sectname = parseName(&sect.sectname); | 254 | const sectname = sectionName(sect.*); |
| 293 | if (mem.eql(u8, segname, "__DWARF")) { | 255 | if (mem.eql(u8, segname, "__DWARF")) { |
| 294 | if (mem.eql(u8, sectname, "__debug_info")) { | 256 | if (mem.eql(u8, sectname, "__debug_info")) { |
| 295 | self.dwarf_debug_info_index = index; | 257 | self.dwarf_debug_info_index = index; |
| ... | @@ -351,7 +313,7 @@ pub fn parseSections(self: *Object) !void { | ... | @@ -351,7 +313,7 @@ pub fn parseSections(self: *Object) !void { |
| 351 | try self.sections.ensureCapacity(self.allocator, seg.sections.items.len); | 313 | try self.sections.ensureCapacity(self.allocator, seg.sections.items.len); |
| 352 | 314 | ||
| 353 | for (seg.sections.items) |sect| { | 315 | for (seg.sections.items) |sect| { |
| 354 | log.debug("parsing section '{s},{s}'", .{ parseName(&sect.segname), parseName(&sect.sectname) }); | 316 | log.debug("parsing section '{s},{s}'", .{ segmentName(sect), sectionName(sect) }); |
| 355 | // Read sections' code | 317 | // Read sections' code |
| 356 | var code = try self.allocator.alloc(u8, @intCast(usize, sect.size)); | 318 | var code = try self.allocator.alloc(u8, @intCast(usize, sect.size)); |
| 357 | _ = try self.file.?.preadAll(code, sect.offset); | 319 | _ = try self.file.?.preadAll(code, sect.offset); |
| ... | @@ -381,47 +343,91 @@ pub fn parseSections(self: *Object) !void { | ... | @@ -381,47 +343,91 @@ pub fn parseSections(self: *Object) !void { |
| 381 | } | 343 | } |
| 382 | } | 344 | } |
| 383 | 345 | ||
| 384 | fn cmpNlist(_: void, lhs: macho.nlist_64, rhs: macho.nlist_64) bool { | 346 | pub fn parseTextBlocks(self: *Object, zld: *Zld) !void { |
| 385 | return lhs.n_value < rhs.n_value; | 347 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; |
| 386 | } | ||
| 387 | 348 | ||
| 388 | fn filterSymsInSection(symbols: []macho.nlist_64, sect_id: u8) []macho.nlist_64 { | 349 | log.warn("analysing {s}", .{self.name.?}); |
| 389 | var start: usize = 0; | ||
| 390 | var end: usize = symbols.len; | ||
| 391 | 350 | ||
| 392 | while (true) { | 351 | const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 393 | var change = false; | 352 | |
| 394 | if (symbols[start].n_sect != sect_id) { | 353 | const SymWithIndex = struct { |
| 395 | start += 1; | 354 | nlist: macho.nlist_64, |
| 396 | change = true; | 355 | index: u32, |
| 356 | |||
| 357 | pub fn cmp(_: void, lhs: @This(), rhs: @This()) bool { | ||
| 358 | return lhs.nlist.n_value < rhs.nlist.n_value; | ||
| 397 | } | 359 | } |
| 398 | if (symbols[end - 1].n_sect != sect_id) { | 360 | |
| 399 | end -= 1; | 361 | fn filterSymsInSection(symbols: []@This(), sect_id: u8) []@This() { |
| 400 | change = true; | 362 | var start: usize = 0; |
| 363 | var end: usize = symbols.len; | ||
| 364 | |||
| 365 | while (true) { | ||
| 366 | var change = false; | ||
| 367 | if (symbols[start].nlist.n_sect != sect_id) { | ||
| 368 | start += 1; | ||
| 369 | change = true; | ||
| 370 | } | ||
| 371 | if (symbols[end - 1].nlist.n_sect != sect_id) { | ||
| 372 | end -= 1; | ||
| 373 | change = true; | ||
| 374 | } | ||
| 375 | |||
| 376 | if (start == end) break; | ||
| 377 | if (!change) break; | ||
| 378 | } | ||
| 379 | |||
| 380 | return symbols[start..end]; | ||
| 401 | } | 381 | } |
| 402 | 382 | ||
| 403 | if (start == end) break; | 383 | fn filterRelocs(relocs: []macho.relocation_info, start: u64, end: u64) []macho.relocation_info { |
| 404 | if (!change) break; | 384 | if (relocs.len == 0) return relocs; |
| 405 | } | ||
| 406 | 385 | ||
| 407 | return symbols[start..end]; | 386 | var start_id: usize = 0; |
| 408 | } | 387 | var end_id: usize = relocs.len; |
| 409 | 388 | ||
| 410 | pub fn parseDummy(self: *Object) !void { | 389 | while (true) { |
| 411 | const seg = self.load_commands.items[self.segment_cmd_index.?].Segment; | 390 | var change = false; |
| 391 | if (relocs[start_id].r_address > end) { | ||
| 392 | start_id += 1; | ||
| 393 | change = true; | ||
| 394 | } | ||
| 395 | if (relocs[end_id - 1].r_address < start) { | ||
| 396 | end_id -= 1; | ||
| 397 | change = true; | ||
| 398 | } | ||
| 412 | 399 | ||
| 413 | log.warn("analysing {s}", .{self.name.?}); | 400 | if (start_id == end_id) break; |
| 401 | if (!change) break; | ||
| 402 | } | ||
| 414 | 403 | ||
| 415 | const dysymtab = self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; | 404 | return relocs[start_id..end_id]; |
| 405 | } | ||
| 406 | }; | ||
| 407 | |||
| 408 | const nlists = self.symtab.items[dysymtab.ilocalsym..dysymtab.iundefsym]; | ||
| 416 | 409 | ||
| 417 | var sorted_syms = std.ArrayList(macho.nlist_64).init(self.allocator); | 410 | var sorted_syms = std.ArrayList(SymWithIndex).init(self.allocator); |
| 418 | defer sorted_syms.deinit(); | 411 | defer sorted_syms.deinit(); |
| 419 | try sorted_syms.appendSlice(self.symtab.items[dysymtab.ilocalsym..dysymtab.iundefsym]); | 412 | try sorted_syms.ensureTotalCapacity(nlists.len); |
| 420 | 413 | ||
| 421 | std.sort.sort(macho.nlist_64, sorted_syms.items, {}, cmpNlist); | 414 | for (nlists) |nlist, index| { |
| 415 | sorted_syms.appendAssumeCapacity(.{ | ||
| 416 | .nlist = nlist, | ||
| 417 | .index = @intCast(u32, index + dysymtab.ilocalsym), | ||
| 418 | }); | ||
| 419 | } | ||
| 420 | |||
| 421 | std.sort.sort(SymWithIndex, sorted_syms.items, {}, SymWithIndex.cmp); | ||
| 422 | 422 | ||
| 423 | for (seg.sections.items) |sect, sect_id| { | 423 | for (seg.sections.items) |sect, sect_id| { |
| 424 | log.warn("section {s},{s}", .{ parseName(&sect.segname), parseName(&sect.sectname) }); | 424 | log.warn("section {s},{s}", .{ segmentName(sect), sectionName(sect) }); |
| 425 | |||
| 426 | const match = (try zld.getMatchingSection(sect)) orelse { | ||
| 427 | log.warn("unhandled section", .{}); | ||
| 428 | continue; | ||
| 429 | }; | ||
| 430 | |||
| 425 | // Read code | 431 | // Read code |
| 426 | var code = try self.allocator.alloc(u8, @intCast(usize, sect.size)); | 432 | var code = try self.allocator.alloc(u8, @intCast(usize, sect.size)); |
| 427 | defer self.allocator.free(code); | 433 | defer self.allocator.free(code); |
| ... | @@ -431,16 +437,25 @@ pub fn parseDummy(self: *Object) !void { | ... | @@ -431,16 +437,25 @@ pub fn parseDummy(self: *Object) !void { |
| 431 | const raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc); | 437 | const raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc); |
| 432 | defer self.allocator.free(raw_relocs); | 438 | defer self.allocator.free(raw_relocs); |
| 433 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); | 439 | _ = try self.file.?.preadAll(raw_relocs, sect.reloff); |
| 440 | const relocs = mem.bytesAsSlice(macho.relocation_info, raw_relocs); | ||
| 434 | 441 | ||
| 435 | const relocs = try reloc.parse( | 442 | const alignment = sect.@"align"; |
| 436 | self.allocator, | ||
| 437 | self.arch.?, | ||
| 438 | code, | ||
| 439 | mem.bytesAsSlice(macho.relocation_info, raw_relocs), | ||
| 440 | ); | ||
| 441 | 443 | ||
| 442 | if (self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) { | 444 | if (self.header.?.flags & macho.MH_SUBSECTIONS_VIA_SYMBOLS != 0) { |
| 443 | const syms = filterSymsInSection(sorted_syms.items, @intCast(u8, sect_id + 1)); | 445 | const syms = SymWithIndex.filterSymsInSection(sorted_syms.items, @intCast(u8, sect_id + 1)); |
| 446 | |||
| 447 | if (syms.len == 0) { | ||
| 448 | // One large text block referenced by section offsets only | ||
| 449 | log.warn("TextBlock", .{}); | ||
| 450 | log.warn(" | referenced by section offsets", .{}); | ||
| 451 | log.warn(" | start_addr = {}", .{sect.addr}); | ||
| 452 | log.warn(" | end_addr = {}", .{sect.size}); | ||
| 453 | log.warn(" | size = {}", .{sect.size}); | ||
| 454 | log.warn(" | alignment = 0x{x}", .{alignment}); | ||
| 455 | log.warn(" | segment_id = {}", .{match.seg}); | ||
| 456 | log.warn(" | section_id = {}", .{match.sect}); | ||
| 457 | log.warn(" | relocs: {any}", .{relocs}); | ||
| 458 | } | ||
| 444 | 459 | ||
| 445 | var indices = std.ArrayList(u32).init(self.allocator); | 460 | var indices = std.ArrayList(u32).init(self.allocator); |
| 446 | defer indices.deinit(); | 461 | defer indices.deinit(); |
| ... | @@ -450,32 +465,35 @@ pub fn parseDummy(self: *Object) !void { | ... | @@ -450,32 +465,35 @@ pub fn parseDummy(self: *Object) !void { |
| 450 | const curr = syms[i]; | 465 | const curr = syms[i]; |
| 451 | try indices.append(i); | 466 | try indices.append(i); |
| 452 | 467 | ||
| 453 | const next: ?macho.nlist_64 = if (i + 1 < syms.len) | 468 | const next: ?SymWithIndex = if (i + 1 < syms.len) |
| 454 | syms[i + 1] | 469 | syms[i + 1] |
| 455 | else | 470 | else |
| 456 | null; | 471 | null; |
| 457 | 472 | ||
| 458 | if (next) |n| { | 473 | if (next) |n| { |
| 459 | if (curr.n_value == n.n_value) { | 474 | if (curr.nlist.n_value == n.nlist.n_value) { |
| 460 | continue; | 475 | continue; |
| 461 | } | 476 | } |
| 462 | } | 477 | } |
| 463 | 478 | ||
| 464 | const start_addr = curr.n_value - sect.addr; | 479 | const start_addr = curr.nlist.n_value - sect.addr; |
| 465 | const end_addr = if (next) |n| n.n_value - sect.addr else sect.size; | 480 | const end_addr = if (next) |n| n.nlist.n_value - sect.addr else sect.size; |
| 466 | const alignment = sect.@"align"; | ||
| 467 | 481 | ||
| 468 | const tb_code = code[start_addr..end_addr]; | 482 | const tb_code = code[start_addr..end_addr]; |
| 469 | const size = tb_code.len; | 483 | const size = tb_code.len; |
| 470 | 484 | ||
| 471 | log.warn("TextBlock", .{}); | 485 | log.warn("TextBlock", .{}); |
| 472 | for (indices.items) |id| { | 486 | for (indices.items) |id| { |
| 473 | log.warn(" | symbol {s}", .{self.getString(syms[id].n_strx)}); | 487 | const sym = self.symbols.items[syms[id].index]; |
| 488 | log.warn(" | symbol = {s}", .{sym.name}); | ||
| 474 | } | 489 | } |
| 475 | log.warn(" | start_addr = 0x{x}", .{start_addr}); | 490 | log.warn(" | start_addr = {}", .{start_addr}); |
| 476 | log.warn(" | end_addr = 0x{x}", .{end_addr}); | 491 | log.warn(" | end_addr = {}", .{end_addr}); |
| 477 | log.warn(" | size = {}", .{size}); | 492 | log.warn(" | size = {}", .{size}); |
| 478 | log.warn(" | alignment = 0x{x}", .{alignment}); | 493 | log.warn(" | alignment = 0x{x}", .{alignment}); |
| 494 | log.warn(" | segment_id = {}", .{match.seg}); | ||
| 495 | log.warn(" | section_id = {}", .{match.sect}); | ||
| 496 | log.warn(" | relocs: {any}", .{SymWithIndex.filterRelocs(relocs, start_addr, end_addr)}); | ||
| 479 | 497 | ||
| 480 | indices.clearRetainingCapacity(); | 498 | indices.clearRetainingCapacity(); |
| 481 | } | 499 | } |
src/link/MachO/Zld.zig+44-41| ... | @@ -234,6 +234,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg | ... | @@ -234,6 +234,7 @@ pub fn link(self: *Zld, files: []const []const u8, output: Output, args: LinkArg |
| 234 | try self.parseInputFiles(files, args.syslibroot); | 234 | try self.parseInputFiles(files, args.syslibroot); |
| 235 | try self.parseLibs(args.libs, args.syslibroot); | 235 | try self.parseLibs(args.libs, args.syslibroot); |
| 236 | try self.resolveSymbols(); | 236 | try self.resolveSymbols(); |
| 237 | try self.parseTextBlocks(); | ||
| 237 | try self.resolveStubsAndGotEntries(); | 238 | try self.resolveStubsAndGotEntries(); |
| 238 | try self.updateMetadata(); | 239 | try self.updateMetadata(); |
| 239 | try self.sortSections(); | 240 | try self.sortSections(); |
| ... | @@ -322,10 +323,10 @@ fn mapAndUpdateSections( | ... | @@ -322,10 +323,10 @@ fn mapAndUpdateSections( |
| 322 | 323 | ||
| 323 | log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{ | 324 | log.debug("{s}: '{s},{s}' mapped to '{s},{s}' from 0x{x} to 0x{x}", .{ |
| 324 | object.name.?, | 325 | object.name.?, |
| 325 | parseName(&source_sect.inner.segname), | 326 | segmentName(source_sect.inner), |
| 326 | parseName(&source_sect.inner.sectname), | 327 | sectionName(source_sect.inner), |
| 327 | parseName(&target_sect.segname), | 328 | segmentName(target_sect.*), |
| 328 | parseName(&target_sect.sectname), | 329 | sectionName(target_sect.*), |
| 329 | offset, | 330 | offset, |
| 330 | offset + size, | 331 | offset + size, |
| 331 | }); | 332 | }); |
| ... | @@ -343,12 +344,12 @@ fn updateMetadata(self: *Zld) !void { | ... | @@ -343,12 +344,12 @@ fn updateMetadata(self: *Zld) !void { |
| 343 | for (self.objects.items) |object| { | 344 | for (self.objects.items) |object| { |
| 344 | // Find ideal section alignment and update section mappings | 345 | // Find ideal section alignment and update section mappings |
| 345 | for (object.sections.items) |sect, sect_id| { | 346 | for (object.sections.items) |sect, sect_id| { |
| 346 | const match = (try self.getMatchingSection(sect)) orelse { | 347 | const match = (try self.getMatchingSection(sect.inner)) orelse { |
| 347 | log.debug("{s}: unhandled section type 0x{x} for '{s},{s}'", .{ | 348 | log.debug("{s}: unhandled section type 0x{x} for '{s},{s}'", .{ |
| 348 | object.name.?, | 349 | object.name.?, |
| 349 | sect.flags(), | 350 | sect.inner.flags, |
| 350 | sect.segname(), | 351 | segmentName(sect.inner), |
| 351 | sect.sectname(), | 352 | sectionName(sect.inner), |
| 352 | }); | 353 | }); |
| 353 | continue; | 354 | continue; |
| 354 | }; | 355 | }; |
| ... | @@ -441,15 +442,15 @@ const MatchingSection = struct { | ... | @@ -441,15 +442,15 @@ const MatchingSection = struct { |
| 441 | sect: u16, | 442 | sect: u16, |
| 442 | }; | 443 | }; |
| 443 | 444 | ||
| 444 | fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { | 445 | pub fn getMatchingSection(self: *Zld, sect: macho.section_64) !?MatchingSection { |
| 445 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 446 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 446 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; | 447 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 447 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 448 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 448 | const segname = sect.segname(); | 449 | const segname = segmentName(sect); |
| 449 | const sectname = sect.sectname(); | 450 | const sectname = sectionName(sect); |
| 450 | 451 | ||
| 451 | const res: ?MatchingSection = blk: { | 452 | const res: ?MatchingSection = blk: { |
| 452 | switch (sect.sectionType()) { | 453 | switch (sectionType(sect)) { |
| 453 | macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { | 454 | macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { |
| 454 | if (self.text_const_section_index == null) { | 455 | if (self.text_const_section_index == null) { |
| 455 | self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); | 456 | self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); |
| ... | @@ -649,7 +650,7 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { | ... | @@ -649,7 +650,7 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { |
| 649 | }; | 650 | }; |
| 650 | }, | 651 | }, |
| 651 | macho.S_REGULAR => { | 652 | macho.S_REGULAR => { |
| 652 | if (sect.isCode()) { | 653 | if (sectionIsCode(sect)) { |
| 653 | if (self.text_section_index == null) { | 654 | if (self.text_section_index == null) { |
| 654 | self.text_section_index = @intCast(u16, text_seg.sections.items.len); | 655 | self.text_section_index = @intCast(u16, text_seg.sections.items.len); |
| 655 | try text_seg.addSection(self.allocator, "__text", .{ | 656 | try text_seg.addSection(self.allocator, "__text", .{ |
| ... | @@ -662,11 +663,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { | ... | @@ -662,11 +663,11 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { |
| 662 | .sect = self.text_section_index.?, | 663 | .sect = self.text_section_index.?, |
| 663 | }; | 664 | }; |
| 664 | } | 665 | } |
| 665 | if (sect.isDebug()) { | 666 | if (sectionIsDebug(sect)) { |
| 666 | // TODO debug attributes | 667 | // TODO debug attributes |
| 667 | if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { | 668 | if (mem.eql(u8, "__LD", segname) and mem.eql(u8, "__compact_unwind", sectname)) { |
| 668 | log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ | 669 | log.debug("TODO compact unwind section: type 0x{x}, name '{s},{s}'", .{ |
| 669 | sect.flags(), segname, sectname, | 670 | sect.flags, segname, sectname, |
| 670 | }); | 671 | }); |
| 671 | } | 672 | } |
| 672 | break :blk null; | 673 | break :blk null; |
| ... | @@ -829,7 +830,7 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { | ... | @@ -829,7 +830,7 @@ fn getMatchingSection(self: *Zld, sect: Object.Section) !?MatchingSection { |
| 829 | 830 | ||
| 830 | if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) { | 831 | if (mem.eql(u8, "__LLVM", segname) and mem.eql(u8, "__asm", sectname)) { |
| 831 | log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{ | 832 | log.debug("TODO LLVM asm section: type 0x{x}, name '{s},{s}'", .{ |
| 832 | sect.flags(), segname, sectname, | 833 | sect.flags, segname, sectname, |
| 833 | }); | 834 | }); |
| 834 | } | 835 | } |
| 835 | 836 | ||
| ... | @@ -956,8 +957,8 @@ fn sortSections(self: *Zld) !void { | ... | @@ -956,8 +957,8 @@ fn sortSections(self: *Zld) !void { |
| 956 | 957 | ||
| 957 | log.debug("remapping in {s}: '{s},{s}': {} => {}", .{ | 958 | log.debug("remapping in {s}: '{s},{s}': {} => {}", .{ |
| 958 | object.name.?, | 959 | object.name.?, |
| 959 | parseName(&sect.inner.segname), | 960 | segmentName(sect.inner), |
| 960 | parseName(&sect.inner.sectname), | 961 | sectionName(sect.inner), |
| 961 | target_map.section_id, | 962 | target_map.section_id, |
| 962 | new_index, | 963 | new_index, |
| 963 | }); | 964 | }); |
| ... | @@ -1086,8 +1087,8 @@ fn allocateSymbol(self: *Zld, symbol: *Symbol) !void { | ... | @@ -1086,8 +1087,8 @@ fn allocateSymbol(self: *Zld, symbol: *Symbol) !void { |
| 1086 | const source_sect = &object.sections.items[reg.section]; | 1087 | const source_sect = &object.sections.items[reg.section]; |
| 1087 | const target_map = source_sect.target_map orelse { | 1088 | const target_map = source_sect.target_map orelse { |
| 1088 | log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{ | 1089 | log.debug("section '{s},{s}' not mapped for symbol '{s}'", .{ |
| 1089 | parseName(&source_sect.inner.segname), | 1090 | segmentName(source_sect.inner), |
| 1090 | parseName(&source_sect.inner.sectname), | 1091 | sectionName(source_sect.inner), |
| 1091 | symbol.name, | 1092 | symbol.name, |
| 1092 | }); | 1093 | }); |
| 1093 | return; | 1094 | return; |
| ... | @@ -1464,7 +1465,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { | ... | @@ -1464,7 +1465,7 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { |
| 1464 | fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { | 1465 | fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { |
| 1465 | log.debug("resolving symbols in '{s}'", .{object.name}); | 1466 | log.debug("resolving symbols in '{s}'", .{object.name}); |
| 1466 | 1467 | ||
| 1467 | for (object.symtab.items) |sym| { | 1468 | for (object.symtab.items) |sym, sym_id| { |
| 1468 | const sym_name = object.getString(sym.n_strx); | 1469 | const sym_name = object.getString(sym.n_strx); |
| 1469 | 1470 | ||
| 1470 | if (Symbol.isStab(sym)) { | 1471 | if (Symbol.isStab(sym)) { |
| ... | @@ -1497,6 +1498,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { | ... | @@ -1497,6 +1498,7 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { |
| 1497 | .file = object, | 1498 | .file = object, |
| 1498 | }, | 1499 | }, |
| 1499 | }; | 1500 | }; |
| 1501 | const index = @intCast(u32, self.locals.items.len); | ||
| 1500 | try self.locals.append(self.allocator, symbol); | 1502 | try self.locals.append(self.allocator, symbol); |
| 1501 | try object.symbols.append(self.allocator, symbol); | 1503 | try object.symbols.append(self.allocator, symbol); |
| 1502 | continue; | 1504 | continue; |
| ... | @@ -1665,6 +1667,12 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1665,6 +1667,12 @@ fn resolveSymbols(self: *Zld) !void { |
| 1665 | if (has_undefined) return error.UndefinedSymbolReference; | 1667 | if (has_undefined) return error.UndefinedSymbolReference; |
| 1666 | } | 1668 | } |
| 1667 | 1669 | ||
| 1670 | fn parseTextBlocks(self: *Zld) !void { | ||
| 1671 | for (self.objects.items) |object| { | ||
| 1672 | try object.parseTextBlocks(self); | ||
| 1673 | } | ||
| 1674 | } | ||
| 1675 | |||
| 1668 | fn resolveStubsAndGotEntries(self: *Zld) !void { | 1676 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1669 | for (self.objects.items) |object| { | 1677 | for (self.objects.items) |object| { |
| 1670 | log.debug("resolving stubs and got entries from {s}", .{object.name}); | 1678 | log.debug("resolving stubs and got entries from {s}", .{object.name}); |
| ... | @@ -1718,11 +1726,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1718,11 +1726,11 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1718 | log.debug("relocating object {s}", .{object.name}); | 1726 | log.debug("relocating object {s}", .{object.name}); |
| 1719 | 1727 | ||
| 1720 | for (object.sections.items) |sect| { | 1728 | for (object.sections.items) |sect| { |
| 1721 | if (sect.inner.flags == macho.S_MOD_INIT_FUNC_POINTERS or | 1729 | if (sectionType(sect.inner) == macho.S_MOD_INIT_FUNC_POINTERS or |
| 1722 | sect.inner.flags == macho.S_MOD_TERM_FUNC_POINTERS) continue; | 1730 | sectionType(sect.inner) == macho.S_MOD_TERM_FUNC_POINTERS) continue; |
| 1723 | 1731 | ||
| 1724 | const segname = parseName(&sect.inner.segname); | 1732 | const segname = segmentName(sect.inner); |
| 1725 | const sectname = parseName(&sect.inner.sectname); | 1733 | const sectname = sectionName(sect.inner); |
| 1726 | 1734 | ||
| 1727 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); | 1735 | log.debug("relocating section '{s},{s}'", .{ segname, sectname }); |
| 1728 | 1736 | ||
| ... | @@ -1759,7 +1767,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1759,7 +1767,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1759 | args.source_target_sect_addr = source_sect.inner.addr; | 1767 | args.source_target_sect_addr = source_sect.inner.addr; |
| 1760 | } | 1768 | } |
| 1761 | 1769 | ||
| 1762 | const flags = @truncate(u8, target_sect.flags & 0xff); | 1770 | const sect_type = sectionType(target_sect); |
| 1763 | const should_rebase = rebase: { | 1771 | const should_rebase = rebase: { |
| 1764 | if (!unsigned.is_64bit) break :rebase false; | 1772 | if (!unsigned.is_64bit) break :rebase false; |
| 1765 | 1773 | ||
| ... | @@ -1780,8 +1788,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1780,8 +1788,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1780 | }; | 1788 | }; |
| 1781 | 1789 | ||
| 1782 | if (!is_right_segment) break :rebase false; | 1790 | if (!is_right_segment) break :rebase false; |
| 1783 | if (flags != macho.S_LITERAL_POINTERS and | 1791 | if (sect_type != macho.S_LITERAL_POINTERS and |
| 1784 | flags != macho.S_REGULAR) | 1792 | sect_type != macho.S_REGULAR) |
| 1785 | { | 1793 | { |
| 1786 | break :rebase false; | 1794 | break :rebase false; |
| 1787 | } | 1795 | } |
| ... | @@ -1804,7 +1812,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1804,7 +1812,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1804 | 1812 | ||
| 1805 | // TLV is handled via a separate offset mechanism. | 1813 | // TLV is handled via a separate offset mechanism. |
| 1806 | // Calculate the offset to the initializer. | 1814 | // Calculate the offset to the initializer. |
| 1807 | if (flags == macho.S_THREAD_LOCAL_VARIABLES) tlv: { | 1815 | if (sect_type == macho.S_THREAD_LOCAL_VARIABLES) tlv: { |
| 1808 | // TODO we don't want to save offset to tlv_bootstrap | 1816 | // TODO we don't want to save offset to tlv_bootstrap |
| 1809 | if (mem.eql(u8, object.symbols.items[rel.target.symbol].name, "__tlv_bootstrap")) break :tlv; | 1817 | if (mem.eql(u8, object.symbols.items[rel.target.symbol].name, "__tlv_bootstrap")) break :tlv; |
| 1810 | 1818 | ||
| ... | @@ -1858,13 +1866,13 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1858,13 +1866,13 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1858 | target_sect_off + sect.code.len, | 1866 | target_sect_off + sect.code.len, |
| 1859 | }); | 1867 | }); |
| 1860 | 1868 | ||
| 1861 | if (target_sect.flags == macho.S_ZEROFILL or | 1869 | if (sectionType(target_sect) == macho.S_ZEROFILL or |
| 1862 | target_sect.flags == macho.S_THREAD_LOCAL_ZEROFILL or | 1870 | sectionType(target_sect) == macho.S_THREAD_LOCAL_ZEROFILL or |
| 1863 | target_sect.flags == macho.S_THREAD_LOCAL_VARIABLES) | 1871 | sectionType(target_sect) == macho.S_THREAD_LOCAL_VARIABLES) |
| 1864 | { | 1872 | { |
| 1865 | log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ | 1873 | log.debug("zeroing out '{s},{s}' from 0x{x} to 0x{x}", .{ |
| 1866 | parseName(&target_sect.segname), | 1874 | segmentName(target_sect), |
| 1867 | parseName(&target_sect.sectname), | 1875 | sectionName(target_sect), |
| 1868 | target_sect_off, | 1876 | target_sect_off, |
| 1869 | target_sect_off + sect.code.len, | 1877 | target_sect_off + sect.code.len, |
| 1870 | }); | 1878 | }); |
| ... | @@ -1926,8 +1934,8 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T | ... | @@ -1926,8 +1934,8 @@ fn relocTargetAddr(self: *Zld, object: *const Object, target: reloc.Relocation.T |
| 1926 | log.debug(" | section offset", .{}); | 1934 | log.debug(" | section offset", .{}); |
| 1927 | const source_sect = object.sections.items[sect_id]; | 1935 | const source_sect = object.sections.items[sect_id]; |
| 1928 | log.debug(" | section '{s},{s}'", .{ | 1936 | log.debug(" | section '{s},{s}'", .{ |
| 1929 | parseName(&source_sect.inner.segname), | 1937 | segmentName(source_sect.inner), |
| 1930 | parseName(&source_sect.inner.sectname), | 1938 | sectionName(source_sect.inner), |
| 1931 | }); | 1939 | }); |
| 1932 | const target_map = source_sect.target_map orelse unreachable; | 1940 | const target_map = source_sect.target_map orelse unreachable; |
| 1933 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; | 1941 | const target_seg = self.load_commands.items[target_map.segment_id].Segment; |
| ... | @@ -2999,8 +3007,3 @@ fn writeHeader(self: *Zld) !void { | ... | @@ -2999,8 +3007,3 @@ fn writeHeader(self: *Zld) !void { |
| 2999 | 3007 | ||
| 3000 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); | 3008 | try self.file.?.pwriteAll(mem.asBytes(&header), 0); |
| 3001 | } | 3009 | } |
| 3002 | |||
| 3003 | pub fn parseName(name: *const [16]u8) []const u8 { | ||
| 3004 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | ||
| 3005 | return name[0..len]; | ||
| 3006 | } |
src/link/MachO/commands.zig+38| ... | @@ -425,6 +425,44 @@ fn makeStaticString(bytes: []const u8) [16]u8 { | ... | @@ -425,6 +425,44 @@ fn makeStaticString(bytes: []const u8) [16]u8 { |
| 425 | return buf; | 425 | return buf; |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | fn parseName(name: *const [16]u8) []const u8 { | ||
| 429 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | ||
| 430 | return name[0..len]; | ||
| 431 | } | ||
| 432 | |||
| 433 | pub fn segmentName(sect: macho.section_64) []const u8 { | ||
| 434 | return parseName(&sect.segname); | ||
| 435 | } | ||
| 436 | |||
| 437 | pub fn sectionName(sect: macho.section_64) []const u8 { | ||
| 438 | return parseName(&sect.sectname); | ||
| 439 | } | ||
| 440 | |||
| 441 | pub fn sectionType(sect: macho.section_64) u8 { | ||
| 442 | return @truncate(u8, sect.flags & 0xff); | ||
| 443 | } | ||
| 444 | |||
| 445 | pub fn sectionAttrs(sect: macho.section_64) u32 { | ||
| 446 | return sect.flags & 0xffffff00; | ||
| 447 | } | ||
| 448 | |||
| 449 | pub fn sectionIsCode(sect: macho.section_64) bool { | ||
| 450 | const attr = sectionAttrs(sect); | ||
| 451 | return attr & macho.S_ATTR_PURE_INSTRUCTIONS != 0 or attr & macho.S_ATTR_SOME_INSTRUCTIONS != 0; | ||
| 452 | } | ||
| 453 | |||
| 454 | pub fn sectionIsDebug(sect: macho.section_64) bool { | ||
| 455 | return sectionAttrs(sect) & macho.S_ATTR_DEBUG != 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | pub fn sectionIsDontDeadStrip(sect: macho.section_64) bool { | ||
| 459 | return sectionAttrs(sect) & macho.S_ATTR_NO_DEAD_STRIP != 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | pub fn sectionIsDontDeadStripIfReferencesLive(sect: macho.section_64) bool { | ||
| 463 | return sectionAttrs(sect) & macho.S_ATTR_LIVE_SUPPORT != 0; | ||
| 464 | } | ||
| 465 | |||
| 428 | fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void { | 466 | fn testRead(allocator: *Allocator, buffer: []const u8, expected: anytype) !void { |
| 429 | var stream = io.fixedBufferStream(buffer); | 467 | var stream = io.fixedBufferStream(buffer); |
| 430 | var given = try LoadCommand.read(allocator, stream.reader()); | 468 | var given = try LoadCommand.read(allocator, stream.reader()); |