| ... | ... | @@ -78,14 +78,9 @@ undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 78 | 78 | externs: std.StringArrayHashMapUnmanaged(Symbol) = .{}, |
| 79 | 79 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 80 | 80 | |
| 81 | | // locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{}, |
| 82 | | // exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{}, |
| 83 | | // nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 84 | | // lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 85 | | // tlv_bootstrap: ?Import = null, |
| 86 | | // threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 87 | | // local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 88 | | // nonlazy_pointers: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 81 | threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 82 | rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 83 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, |
| 89 | 84 | |
| 90 | 85 | stub_helper_stubs_start_off: ?u64 = null, |
| 91 | 86 | |
| ... | ... | @@ -279,12 +274,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 279 | 274 | try self.populateMetadata(); |
| 280 | 275 | try self.parseInputFiles(files); |
| 281 | 276 | try self.resolveSymbols(); |
| 282 | | self.printSymtab(); |
| 283 | | // try self.sortSections(); |
| 284 | | // try self.allocateTextSegment(); |
| 285 | | // try self.allocateDataConstSegment(); |
| 286 | | // try self.allocateDataSegment(); |
| 287 | | // self.allocateLinkeditSegment(); |
| 277 | try self.updateMetadata(); |
| 278 | try self.sortSections(); |
| 279 | try self.allocateTextSegment(); |
| 280 | try self.allocateDataConstSegment(); |
| 281 | try self.allocateDataSegment(); |
| 282 | self.allocateLinkeditSegment(); |
| 288 | 283 | // try self.writeStubHelperCommon(); |
| 289 | 284 | // try self.doRelocs(); |
| 290 | 285 | // try self.flush(); |
| ... | ... | @@ -403,28 +398,69 @@ fn mapAndUpdateSections( |
| 403 | 398 | target_sect.size = offset + size; |
| 404 | 399 | } |
| 405 | 400 | |
| 406 | | fn updateMetadata(self: *Zld, object_id: u16) !void { |
| 407 | | const object = self.objects.items[object_id]; |
| 408 | | const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 409 | | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 410 | | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 411 | | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 412 | | |
| 413 | | // Create missing metadata |
| 414 | | for (object_seg.sections.items) |source_sect, id| { |
| 415 | | if (id == object.text_section_index.?) continue; |
| 416 | | const segname = parseName(&source_sect.segname); |
| 417 | | const sectname = parseName(&source_sect.sectname); |
| 418 | | const flags = source_sect.flags; |
| 419 | | |
| 420 | | switch (flags) { |
| 421 | | macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { |
| 422 | | if (mem.eql(u8, segname, "__TEXT")) { |
| 423 | | if (self.text_const_section_index != null) continue; |
| 401 | fn updateMetadata(self: *Zld) !void { |
| 402 | for (self.objects.items) |object, id| { |
| 403 | const object_id = @intCast(u16, id); |
| 404 | const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 405 | const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 406 | const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 407 | const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 424 | 408 | |
| 425 | | self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); |
| 409 | // Create missing metadata |
| 410 | for (object_seg.sections.items) |source_sect, sect_id| { |
| 411 | if (sect_id == object.text_section_index.?) continue; |
| 412 | const segname = parseName(&source_sect.segname); |
| 413 | const sectname = parseName(&source_sect.sectname); |
| 414 | const flags = source_sect.flags; |
| 415 | |
| 416 | switch (flags) { |
| 417 | macho.S_REGULAR, macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { |
| 418 | if (mem.eql(u8, segname, "__TEXT")) { |
| 419 | if (self.text_const_section_index != null) continue; |
| 420 | |
| 421 | self.text_const_section_index = @intCast(u16, text_seg.sections.items.len); |
| 422 | try text_seg.addSection(self.allocator, .{ |
| 423 | .sectname = makeStaticString("__const"), |
| 424 | .segname = makeStaticString("__TEXT"), |
| 425 | .addr = 0, |
| 426 | .size = 0, |
| 427 | .offset = 0, |
| 428 | .@"align" = 0, |
| 429 | .reloff = 0, |
| 430 | .nreloc = 0, |
| 431 | .flags = macho.S_REGULAR, |
| 432 | .reserved1 = 0, |
| 433 | .reserved2 = 0, |
| 434 | .reserved3 = 0, |
| 435 | }); |
| 436 | } else if (mem.eql(u8, segname, "__DATA")) { |
| 437 | if (!mem.eql(u8, sectname, "__const")) continue; |
| 438 | if (self.data_const_section_index != null) continue; |
| 439 | |
| 440 | self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 441 | try data_const_seg.addSection(self.allocator, .{ |
| 442 | .sectname = makeStaticString("__const"), |
| 443 | .segname = makeStaticString("__DATA_CONST"), |
| 444 | .addr = 0, |
| 445 | .size = 0, |
| 446 | .offset = 0, |
| 447 | .@"align" = 0, |
| 448 | .reloff = 0, |
| 449 | .nreloc = 0, |
| 450 | .flags = macho.S_REGULAR, |
| 451 | .reserved1 = 0, |
| 452 | .reserved2 = 0, |
| 453 | .reserved3 = 0, |
| 454 | }); |
| 455 | } |
| 456 | }, |
| 457 | macho.S_CSTRING_LITERALS => { |
| 458 | if (!mem.eql(u8, segname, "__TEXT")) continue; |
| 459 | if (self.cstring_section_index != null) continue; |
| 460 | |
| 461 | self.cstring_section_index = @intCast(u16, text_seg.sections.items.len); |
| 426 | 462 | try text_seg.addSection(self.allocator, .{ |
| 427 | | .sectname = makeStaticString("__const"), |
| 463 | .sectname = makeStaticString("__cstring"), |
| 428 | 464 | .segname = makeStaticString("__TEXT"), |
| 429 | 465 | .addr = 0, |
| 430 | 466 | .size = 0, |
| ... | ... | @@ -432,18 +468,19 @@ fn updateMetadata(self: *Zld, object_id: u16) !void { |
| 432 | 468 | .@"align" = 0, |
| 433 | 469 | .reloff = 0, |
| 434 | 470 | .nreloc = 0, |
| 435 | | .flags = macho.S_REGULAR, |
| 471 | .flags = macho.S_CSTRING_LITERALS, |
| 436 | 472 | .reserved1 = 0, |
| 437 | 473 | .reserved2 = 0, |
| 438 | 474 | .reserved3 = 0, |
| 439 | 475 | }); |
| 440 | | } else if (mem.eql(u8, segname, "__DATA")) { |
| 441 | | if (!mem.eql(u8, sectname, "__const")) continue; |
| 442 | | if (self.data_const_section_index != null) continue; |
| 476 | }, |
| 477 | macho.S_MOD_INIT_FUNC_POINTERS => { |
| 478 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 479 | if (self.mod_init_func_section_index != null) continue; |
| 443 | 480 | |
| 444 | | self.data_const_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 481 | self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 445 | 482 | try data_const_seg.addSection(self.allocator, .{ |
| 446 | | .sectname = makeStaticString("__const"), |
| 483 | .sectname = makeStaticString("__mod_init_func"), |
| 447 | 484 | .segname = makeStaticString("__DATA_CONST"), |
| 448 | 485 | .addr = 0, |
| 449 | 486 | .size = 0, |
| ... | ... | @@ -451,183 +488,143 @@ fn updateMetadata(self: *Zld, object_id: u16) !void { |
| 451 | 488 | .@"align" = 0, |
| 452 | 489 | .reloff = 0, |
| 453 | 490 | .nreloc = 0, |
| 454 | | .flags = macho.S_REGULAR, |
| 491 | .flags = macho.S_MOD_INIT_FUNC_POINTERS, |
| 455 | 492 | .reserved1 = 0, |
| 456 | 493 | .reserved2 = 0, |
| 457 | 494 | .reserved3 = 0, |
| 458 | 495 | }); |
| 459 | | } |
| 460 | | }, |
| 461 | | macho.S_CSTRING_LITERALS => { |
| 462 | | if (!mem.eql(u8, segname, "__TEXT")) continue; |
| 463 | | if (self.cstring_section_index != null) continue; |
| 464 | | |
| 465 | | self.cstring_section_index = @intCast(u16, text_seg.sections.items.len); |
| 466 | | try text_seg.addSection(self.allocator, .{ |
| 467 | | .sectname = makeStaticString("__cstring"), |
| 468 | | .segname = makeStaticString("__TEXT"), |
| 469 | | .addr = 0, |
| 470 | | .size = 0, |
| 471 | | .offset = 0, |
| 472 | | .@"align" = 0, |
| 473 | | .reloff = 0, |
| 474 | | .nreloc = 0, |
| 475 | | .flags = macho.S_CSTRING_LITERALS, |
| 476 | | .reserved1 = 0, |
| 477 | | .reserved2 = 0, |
| 478 | | .reserved3 = 0, |
| 479 | | }); |
| 480 | | }, |
| 481 | | macho.S_MOD_INIT_FUNC_POINTERS => { |
| 482 | | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 483 | | if (self.mod_init_func_section_index != null) continue; |
| 484 | | |
| 485 | | self.mod_init_func_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 486 | | try data_const_seg.addSection(self.allocator, .{ |
| 487 | | .sectname = makeStaticString("__mod_init_func"), |
| 488 | | .segname = makeStaticString("__DATA_CONST"), |
| 489 | | .addr = 0, |
| 490 | | .size = 0, |
| 491 | | .offset = 0, |
| 492 | | .@"align" = 0, |
| 493 | | .reloff = 0, |
| 494 | | .nreloc = 0, |
| 495 | | .flags = macho.S_MOD_INIT_FUNC_POINTERS, |
| 496 | | .reserved1 = 0, |
| 497 | | .reserved2 = 0, |
| 498 | | .reserved3 = 0, |
| 499 | | }); |
| 500 | | }, |
| 501 | | macho.S_MOD_TERM_FUNC_POINTERS => { |
| 502 | | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 503 | | if (self.mod_term_func_section_index != null) continue; |
| 504 | | |
| 505 | | self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 506 | | try data_const_seg.addSection(self.allocator, .{ |
| 507 | | .sectname = makeStaticString("__mod_term_func"), |
| 508 | | .segname = makeStaticString("__DATA_CONST"), |
| 509 | | .addr = 0, |
| 510 | | .size = 0, |
| 511 | | .offset = 0, |
| 512 | | .@"align" = 0, |
| 513 | | .reloff = 0, |
| 514 | | .nreloc = 0, |
| 515 | | .flags = macho.S_MOD_TERM_FUNC_POINTERS, |
| 516 | | .reserved1 = 0, |
| 517 | | .reserved2 = 0, |
| 518 | | .reserved3 = 0, |
| 519 | | }); |
| 520 | | }, |
| 521 | | macho.S_ZEROFILL => { |
| 522 | | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 523 | | if (self.bss_section_index != null) continue; |
| 524 | | |
| 525 | | self.bss_section_index = @intCast(u16, data_seg.sections.items.len); |
| 526 | | try data_seg.addSection(self.allocator, .{ |
| 527 | | .sectname = makeStaticString("__bss"), |
| 528 | | .segname = makeStaticString("__DATA"), |
| 529 | | .addr = 0, |
| 530 | | .size = 0, |
| 531 | | .offset = 0, |
| 532 | | .@"align" = 0, |
| 533 | | .reloff = 0, |
| 534 | | .nreloc = 0, |
| 535 | | .flags = macho.S_ZEROFILL, |
| 536 | | .reserved1 = 0, |
| 537 | | .reserved2 = 0, |
| 538 | | .reserved3 = 0, |
| 539 | | }); |
| 540 | | }, |
| 541 | | macho.S_THREAD_LOCAL_VARIABLES => { |
| 542 | | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 543 | | if (self.tlv_section_index != null) continue; |
| 544 | | |
| 545 | | self.tlv_section_index = @intCast(u16, data_seg.sections.items.len); |
| 546 | | try data_seg.addSection(self.allocator, .{ |
| 547 | | .sectname = makeStaticString("__thread_vars"), |
| 548 | | .segname = makeStaticString("__DATA"), |
| 549 | | .addr = 0, |
| 550 | | .size = 0, |
| 551 | | .offset = 0, |
| 552 | | .@"align" = 0, |
| 553 | | .reloff = 0, |
| 554 | | .nreloc = 0, |
| 555 | | .flags = macho.S_THREAD_LOCAL_VARIABLES, |
| 556 | | .reserved1 = 0, |
| 557 | | .reserved2 = 0, |
| 558 | | .reserved3 = 0, |
| 559 | | }); |
| 560 | | }, |
| 561 | | macho.S_THREAD_LOCAL_REGULAR => { |
| 562 | | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 563 | | if (self.tlv_data_section_index != null) continue; |
| 564 | | |
| 565 | | self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len); |
| 566 | | try data_seg.addSection(self.allocator, .{ |
| 567 | | .sectname = makeStaticString("__thread_data"), |
| 568 | | .segname = makeStaticString("__DATA"), |
| 569 | | .addr = 0, |
| 570 | | .size = 0, |
| 571 | | .offset = 0, |
| 572 | | .@"align" = 0, |
| 573 | | .reloff = 0, |
| 574 | | .nreloc = 0, |
| 575 | | .flags = macho.S_THREAD_LOCAL_REGULAR, |
| 576 | | .reserved1 = 0, |
| 577 | | .reserved2 = 0, |
| 578 | | .reserved3 = 0, |
| 579 | | }); |
| 580 | | }, |
| 581 | | macho.S_THREAD_LOCAL_ZEROFILL => { |
| 582 | | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 583 | | if (self.tlv_bss_section_index != null) continue; |
| 584 | | |
| 585 | | self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len); |
| 586 | | try data_seg.addSection(self.allocator, .{ |
| 587 | | .sectname = makeStaticString("__thread_bss"), |
| 588 | | .segname = makeStaticString("__DATA"), |
| 589 | | .addr = 0, |
| 590 | | .size = 0, |
| 591 | | .offset = 0, |
| 592 | | .@"align" = 0, |
| 593 | | .reloff = 0, |
| 594 | | .nreloc = 0, |
| 595 | | .flags = macho.S_THREAD_LOCAL_ZEROFILL, |
| 596 | | .reserved1 = 0, |
| 597 | | .reserved2 = 0, |
| 598 | | .reserved3 = 0, |
| 599 | | }); |
| 600 | | }, |
| 601 | | else => { |
| 602 | | log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); |
| 603 | | }, |
| 604 | | } |
| 605 | | } |
| 496 | }, |
| 497 | macho.S_MOD_TERM_FUNC_POINTERS => { |
| 498 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 499 | if (self.mod_term_func_section_index != null) continue; |
| 606 | 500 | |
| 607 | | // Find ideal section alignment. |
| 608 | | for (object_seg.sections.items) |source_sect, id| { |
| 609 | | if (self.getMatchingSection(source_sect)) |res| { |
| 610 | | const target_seg = &self.load_commands.items[res.seg].Segment; |
| 611 | | const target_sect = &target_seg.sections.items[res.sect]; |
| 612 | | target_sect.@"align" = math.max(target_sect.@"align", source_sect.@"align"); |
| 501 | self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len); |
| 502 | try data_const_seg.addSection(self.allocator, .{ |
| 503 | .sectname = makeStaticString("__mod_term_func"), |
| 504 | .segname = makeStaticString("__DATA_CONST"), |
| 505 | .addr = 0, |
| 506 | .size = 0, |
| 507 | .offset = 0, |
| 508 | .@"align" = 0, |
| 509 | .reloff = 0, |
| 510 | .nreloc = 0, |
| 511 | .flags = macho.S_MOD_TERM_FUNC_POINTERS, |
| 512 | .reserved1 = 0, |
| 513 | .reserved2 = 0, |
| 514 | .reserved3 = 0, |
| 515 | }); |
| 516 | }, |
| 517 | macho.S_ZEROFILL => { |
| 518 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 519 | if (self.bss_section_index != null) continue; |
| 520 | |
| 521 | self.bss_section_index = @intCast(u16, data_seg.sections.items.len); |
| 522 | try data_seg.addSection(self.allocator, .{ |
| 523 | .sectname = makeStaticString("__bss"), |
| 524 | .segname = makeStaticString("__DATA"), |
| 525 | .addr = 0, |
| 526 | .size = 0, |
| 527 | .offset = 0, |
| 528 | .@"align" = 0, |
| 529 | .reloff = 0, |
| 530 | .nreloc = 0, |
| 531 | .flags = macho.S_ZEROFILL, |
| 532 | .reserved1 = 0, |
| 533 | .reserved2 = 0, |
| 534 | .reserved3 = 0, |
| 535 | }); |
| 536 | }, |
| 537 | macho.S_THREAD_LOCAL_VARIABLES => { |
| 538 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 539 | if (self.tlv_section_index != null) continue; |
| 540 | |
| 541 | self.tlv_section_index = @intCast(u16, data_seg.sections.items.len); |
| 542 | try data_seg.addSection(self.allocator, .{ |
| 543 | .sectname = makeStaticString("__thread_vars"), |
| 544 | .segname = makeStaticString("__DATA"), |
| 545 | .addr = 0, |
| 546 | .size = 0, |
| 547 | .offset = 0, |
| 548 | .@"align" = 0, |
| 549 | .reloff = 0, |
| 550 | .nreloc = 0, |
| 551 | .flags = macho.S_THREAD_LOCAL_VARIABLES, |
| 552 | .reserved1 = 0, |
| 553 | .reserved2 = 0, |
| 554 | .reserved3 = 0, |
| 555 | }); |
| 556 | }, |
| 557 | macho.S_THREAD_LOCAL_REGULAR => { |
| 558 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 559 | if (self.tlv_data_section_index != null) continue; |
| 560 | |
| 561 | self.tlv_data_section_index = @intCast(u16, data_seg.sections.items.len); |
| 562 | try data_seg.addSection(self.allocator, .{ |
| 563 | .sectname = makeStaticString("__thread_data"), |
| 564 | .segname = makeStaticString("__DATA"), |
| 565 | .addr = 0, |
| 566 | .size = 0, |
| 567 | .offset = 0, |
| 568 | .@"align" = 0, |
| 569 | .reloff = 0, |
| 570 | .nreloc = 0, |
| 571 | .flags = macho.S_THREAD_LOCAL_REGULAR, |
| 572 | .reserved1 = 0, |
| 573 | .reserved2 = 0, |
| 574 | .reserved3 = 0, |
| 575 | }); |
| 576 | }, |
| 577 | macho.S_THREAD_LOCAL_ZEROFILL => { |
| 578 | if (!mem.eql(u8, segname, "__DATA")) continue; |
| 579 | if (self.tlv_bss_section_index != null) continue; |
| 580 | |
| 581 | self.tlv_bss_section_index = @intCast(u16, data_seg.sections.items.len); |
| 582 | try data_seg.addSection(self.allocator, .{ |
| 583 | .sectname = makeStaticString("__thread_bss"), |
| 584 | .segname = makeStaticString("__DATA"), |
| 585 | .addr = 0, |
| 586 | .size = 0, |
| 587 | .offset = 0, |
| 588 | .@"align" = 0, |
| 589 | .reloff = 0, |
| 590 | .nreloc = 0, |
| 591 | .flags = macho.S_THREAD_LOCAL_ZEROFILL, |
| 592 | .reserved1 = 0, |
| 593 | .reserved2 = 0, |
| 594 | .reserved3 = 0, |
| 595 | }); |
| 596 | }, |
| 597 | else => { |
| 598 | log.debug("unhandled section type 0x{x} for '{s}/{s}'", .{ flags, segname, sectname }); |
| 599 | }, |
| 600 | } |
| 613 | 601 | } |
| 614 | | } |
| 615 | 602 | |
| 616 | | // Update section mappings |
| 617 | | for (object_seg.sections.items) |source_sect, id| { |
| 618 | | const source_sect_id = @intCast(u16, id); |
| 619 | | if (self.getMatchingSection(source_sect)) |res| { |
| 620 | | try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect); |
| 621 | | continue; |
| 603 | // Find ideal section alignment. |
| 604 | for (object_seg.sections.items) |source_sect| { |
| 605 | if (self.getMatchingSection(source_sect)) |res| { |
| 606 | const target_seg = &self.load_commands.items[res.seg].Segment; |
| 607 | const target_sect = &target_seg.sections.items[res.sect]; |
| 608 | target_sect.@"align" = math.max(target_sect.@"align", source_sect.@"align"); |
| 609 | } |
| 622 | 610 | } |
| 623 | 611 | |
| 624 | | const segname = parseName(&source_sect.segname); |
| 625 | | const sectname = parseName(&source_sect.sectname); |
| 626 | | log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); |
| 627 | | try self.unhandled_sections.putNoClobber(self.allocator, .{ |
| 628 | | .object_id = object_id, |
| 629 | | .source_sect_id = source_sect_id, |
| 630 | | }, 0); |
| 612 | // Update section mappings |
| 613 | for (object_seg.sections.items) |source_sect, sect_id| { |
| 614 | const source_sect_id = @intCast(u16, sect_id); |
| 615 | if (self.getMatchingSection(source_sect)) |res| { |
| 616 | try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect); |
| 617 | continue; |
| 618 | } |
| 619 | |
| 620 | const segname = parseName(&source_sect.segname); |
| 621 | const sectname = parseName(&source_sect.sectname); |
| 622 | log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname }); |
| 623 | try self.unhandled_sections.putNoClobber(self.allocator, .{ |
| 624 | .object_id = object_id, |
| 625 | .source_sect_id = source_sect_id, |
| 626 | }, 0); |
| 627 | } |
| 631 | 628 | } |
| 632 | 629 | } |
| 633 | 630 | |
| ... | ... | @@ -826,7 +823,10 @@ fn sortSections(self: *Zld) !void { |
| 826 | 823 | |
| 827 | 824 | fn allocateTextSegment(self: *Zld) !void { |
| 828 | 825 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 829 | | const nexterns = @intCast(u32, self.lazy_imports.items().len); |
| 826 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined |
| 827 | // object files. For the time being, assume all externs are stubs (this is wasting space but should |
| 828 | // correspond to the worst-case upper bound). |
| 829 | const nstubs = @intCast(u32, self.externs.count()); |
| 830 | 830 | |
| 831 | 831 | const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize; |
| 832 | 832 | seg.inner.fileoff = 0; |
| ... | ... | @@ -835,14 +835,14 @@ fn allocateTextSegment(self: *Zld) !void { |
| 835 | 835 | // Set stubs and stub_helper sizes |
| 836 | 836 | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 837 | 837 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; |
| 838 | | stubs.size += nexterns * stubs.reserved2; |
| 838 | stubs.size += nstubs * stubs.reserved2; |
| 839 | 839 | |
| 840 | 840 | const stub_size: u4 = switch (self.arch.?) { |
| 841 | 841 | .x86_64 => 10, |
| 842 | 842 | .aarch64 => 3 * @sizeOf(u32), |
| 843 | 843 | else => unreachable, |
| 844 | 844 | }; |
| 845 | | stub_helper.size += nexterns * stub_size; |
| 845 | stub_helper.size += nstubs * stub_size; |
| 846 | 846 | |
| 847 | 847 | var sizeofcmds: u64 = 0; |
| 848 | 848 | for (self.load_commands.items) |lc| { |
| ... | ... | @@ -877,7 +877,10 @@ fn allocateTextSegment(self: *Zld) !void { |
| 877 | 877 | |
| 878 | 878 | fn allocateDataConstSegment(self: *Zld) !void { |
| 879 | 879 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 880 | | const nonlazy = @intCast(u32, self.nonlazy_imports.items().len); |
| 880 | // TODO This should be worked out by scanning the relocations in the __text sections of all |
| 881 | // combined object files. For the time being, assume all externs are GOT entries (this is wasting space but |
| 882 | // should correspond to the worst-case upper bound). |
| 883 | const nexterns = @intCast(u32, self.externs.count()); |
| 881 | 884 | |
| 882 | 885 | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 883 | 886 | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; |
| ... | ... | @@ -888,14 +891,17 @@ fn allocateDataConstSegment(self: *Zld) !void { |
| 888 | 891 | // TODO this will require scanning the relocations at least one to work out |
| 889 | 892 | // the exact amount of local GOT indirections. For the time being, set some |
| 890 | 893 | // default value. |
| 891 | | got.size += (max_local_got_indirections + nonlazy) * @sizeOf(u64); |
| 894 | got.size += (max_local_got_indirections + nexterns) * @sizeOf(u64); |
| 892 | 895 | |
| 893 | 896 | try self.allocateSegment(self.data_const_segment_cmd_index.?, 0); |
| 894 | 897 | } |
| 895 | 898 | |
| 896 | 899 | fn allocateDataSegment(self: *Zld) !void { |
| 897 | 900 | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 898 | | const lazy = @intCast(u32, self.lazy_imports.items().len); |
| 901 | // TODO This should be worked out by scanning the relocations in the __text sections of all combined |
| 902 | // object files. For the time being, assume all externs are stubs (this is wasting space but should |
| 903 | // correspond to the worst-case upper bound). |
| 904 | const nstubs = @intCast(u32, self.externs.count()); |
| 899 | 905 | |
| 900 | 906 | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 901 | 907 | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| ... | ... | @@ -904,8 +910,8 @@ fn allocateDataSegment(self: *Zld) !void { |
| 904 | 910 | // Set la_symbol_ptr and data size |
| 905 | 911 | const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?]; |
| 906 | 912 | const data = &seg.sections.items[self.data_section_index.?]; |
| 907 | | la_symbol_ptr.size += lazy * @sizeOf(u64); |
| 908 | | data.size += @sizeOf(u64); // TODO when do we need more? |
| 913 | la_symbol_ptr.size += nstubs * @sizeOf(u64); |
| 914 | data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder |
| 909 | 915 | |
| 910 | 916 | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| 911 | 917 | } |
| ... | ... | @@ -1303,7 +1309,13 @@ fn resolveSymbols(self: *Zld) !void { |
| 1303 | 1309 | while (self.undefs.items().len > 0) { |
| 1304 | 1310 | const entry = self.undefs.pop(); |
| 1305 | 1311 | try self.externs.putNoClobber(self.allocator, entry.key, .{ |
| 1306 | | .inner = entry.value.inner, |
| 1312 | .inner = .{ |
| 1313 | .n_strx = 0, // This will be populated once we write the string table. |
| 1314 | .n_type = macho.N_UNDF | macho.N_EXT, |
| 1315 | .n_sect = 0, |
| 1316 | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, |
| 1317 | .n_value = 0, |
| 1318 | }, |
| 1307 | 1319 | .file = 0, |
| 1308 | 1320 | }); |
| 1309 | 1321 | } |
| ... | ... | @@ -1316,6 +1328,19 @@ fn resolveSymbols(self: *Zld) !void { |
| 1316 | 1328 | |
| 1317 | 1329 | return error.UndefinedSymbolReference; |
| 1318 | 1330 | } |
| 1331 | |
| 1332 | // Finally, put in a reference to 'dyld_stub_binder'. |
| 1333 | const name = try self.allocator.dupe(u8, "dyld_stub_binder"); |
| 1334 | try self.externs.putNoClobber(self.allocator, name, .{ |
| 1335 | .inner = .{ |
| 1336 | .n_strx = 0, // This will be populated once we write the string table. |
| 1337 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| 1338 | .n_sect = 0, |
| 1339 | .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER, |
| 1340 | .n_value = 0, |
| 1341 | }, |
| 1342 | .file = 0, |
| 1343 | }); |
| 1319 | 1344 | } |
| 1320 | 1345 | |
| 1321 | 1346 | fn doRelocs(self: *Zld) !void { |
| ... | ... | @@ -1879,10 +1904,33 @@ fn doRelocs(self: *Zld) !void { |
| 1879 | 1904 | fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 { |
| 1880 | 1905 | const object = self.objects.items[object_id]; |
| 1881 | 1906 | const seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 1907 | |
| 1908 | const is_got: bool = is_got: { |
| 1909 | switch (self.arch.?) { |
| 1910 | .x86_64 => { |
| 1911 | const rel_type = @intToEnum(macho.reloc_type_x86_64, rel.r_type); |
| 1912 | break :is_got = switch (rel_type) { |
| 1913 | .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => true, |
| 1914 | else => false, |
| 1915 | }; |
| 1916 | }, |
| 1917 | .aarch64 => { |
| 1918 | const rel_type = @intToEnum(macho.reloc_type_aarch64, rel.r_type); |
| 1919 | break :is_got = switch (rel_type) { |
| 1920 | .ARM64_RELOC_GOT_LOAD_PAGE21, |
| 1921 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, |
| 1922 | .ARM64_RELOC_POINTER_TO_GOT, |
| 1923 | => true, |
| 1924 | else => false, |
| 1925 | }; |
| 1926 | }, |
| 1927 | } |
| 1928 | }; |
| 1929 | |
| 1882 | 1930 | const target_addr = blk: { |
| 1883 | 1931 | if (rel.r_extern == 1) { |
| 1884 | 1932 | const sym = object.symtab.items[rel.r_symbolnum]; |
| 1885 | | if (isLocal(&sym) or isExport(&sym)) { |
| 1933 | if (sym.isSect()) { |
| 1886 | 1934 | // Relocate using section offsets only. |
| 1887 | 1935 | const target_mapping = self.mappings.get(.{ |
| 1888 | 1936 | .object_id = object_id, |
| ... | ... | @@ -1894,30 +1942,13 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 |
| 1894 | 1942 | const target_sect_addr = target_sect.addr + target_mapping.offset; |
| 1895 | 1943 | log.debug(" | symbol local to object", .{}); |
| 1896 | 1944 | break :blk target_sect_addr + sym.n_value - source_sect.addr; |
| 1897 | | } else if (isImport(&sym)) { |
| 1898 | | // Relocate to either the artifact's local symbol, or an import from |
| 1945 | } else if (sym.isUndf()) { |
| 1946 | // Relocate to either the global symbol, or an import from |
| 1899 | 1947 | // shared library. |
| 1900 | 1948 | const sym_name = object.getString(sym.n_strx); |
| 1901 | | if (self.locals.get(sym_name)) |locs| { |
| 1902 | | var n_value: ?u64 = null; |
| 1903 | | for (locs.items) |loc| { |
| 1904 | | switch (loc.tt) { |
| 1905 | | .Global => { |
| 1906 | | n_value = loc.inner.n_value; |
| 1907 | | break; |
| 1908 | | }, |
| 1909 | | .WeakGlobal => { |
| 1910 | | n_value = loc.inner.n_value; |
| 1911 | | }, |
| 1912 | | .Local => {}, |
| 1913 | | } |
| 1914 | | } |
| 1915 | | if (n_value) |v| { |
| 1916 | | break :blk v; |
| 1917 | | } |
| 1918 | | log.err("local symbol export '{s}' not found", .{sym_name}); |
| 1919 | | return error.LocalSymbolExportNotFound; |
| 1920 | | } else if (self.lazy_imports.get(sym_name)) |ext| { |
| 1949 | if (self.globals.get(sym_name)) |glob| { |
| 1950 | break :blk glob.inner.n_value; |
| 1951 | } else if (self.externs.getEntry(sym_name)) |ext| { |
| 1921 | 1952 | const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1922 | 1953 | const stubs = segment.sections.items[self.stubs_section_index.?]; |
| 1923 | 1954 | break :blk stubs.addr + ext.index * stubs.reserved2; |
| ... | ... | @@ -1928,7 +1959,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 |
| 1928 | 1959 | } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) { |
| 1929 | 1960 | const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1930 | 1961 | const tlv = segment.sections.items[self.tlv_section_index.?]; |
| 1931 | | break :blk tlv.addr + self.tlv_bootstrap.?.index * @sizeOf(u64); |
| 1962 | break :blk tlv.addr; |
| 1932 | 1963 | } else { |
| 1933 | 1964 | log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name}); |
| 1934 | 1965 | return error.FailedToResolveRelocationTarget; |
| ... | ... | @@ -1951,6 +1982,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 |
| 1951 | 1982 | break :blk target_sect.addr + target_mapping.offset; |
| 1952 | 1983 | } |
| 1953 | 1984 | }; |
| 1985 | |
| 1954 | 1986 | return target_addr; |
| 1955 | 1987 | } |
| 1956 | 1988 | |