authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-01 17:29:48+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
log04659f5b82cadb60112f00466ce1ce5b24b562f1
treee803d78f3412b2f34710e81a0e05e9f79eb3d31b
parent116ea1bf2c7b3dd722beb1b4cf8d6e7e9755294f

zld: allocate segments based on worst-case and upper-limit


1 files changed, 273 insertions(+), 241 deletions(-)

src/link/MachO/Zld.zig+273-241
...@@ -78,14 +78,9 @@ undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{},...@@ -78,14 +78,9 @@ undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
78externs: std.StringArrayHashMapUnmanaged(Symbol) = .{},78externs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
79strtab: std.ArrayListUnmanaged(u8) = .{},79strtab: std.ArrayListUnmanaged(u8) = .{},
8080
81// locals: std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(Symbol)) = .{},81threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
82// exports: std.StringArrayHashMapUnmanaged(macho.nlist_64) = .{},82rebases: std.ArrayListUnmanaged(Pointer) = .{},
83// nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{},83got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
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) = .{},
8984
90stub_helper_stubs_start_off: ?u64 = null,85stub_helper_stubs_start_off: ?u64 = null,
9186
...@@ -279,12 +274,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {...@@ -279,12 +274,12 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
279 try self.populateMetadata();274 try self.populateMetadata();
280 try self.parseInputFiles(files);275 try self.parseInputFiles(files);
281 try self.resolveSymbols();276 try self.resolveSymbols();
282 self.printSymtab();277 try self.updateMetadata();
283 // try self.sortSections();278 try self.sortSections();
284 // try self.allocateTextSegment();279 try self.allocateTextSegment();
285 // try self.allocateDataConstSegment();280 try self.allocateDataConstSegment();
286 // try self.allocateDataSegment();281 try self.allocateDataSegment();
287 // self.allocateLinkeditSegment();282 self.allocateLinkeditSegment();
288 // try self.writeStubHelperCommon();283 // try self.writeStubHelperCommon();
289 // try self.doRelocs();284 // try self.doRelocs();
290 // try self.flush();285 // try self.flush();
...@@ -403,28 +398,69 @@ fn mapAndUpdateSections(...@@ -403,28 +398,69 @@ fn mapAndUpdateSections(
403 target_sect.size = offset + size;398 target_sect.size = offset + size;
404}399}
405400
406fn updateMetadata(self: *Zld, object_id: u16) !void {401fn updateMetadata(self: *Zld) !void {
407 const object = self.objects.items[object_id];402 for (self.objects.items) |object, id| {
408 const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;403 const object_id = @intCast(u16, id);
409 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;404 const object_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
410 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;405 const text_seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
411 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;406 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
412407 const data_seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
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;
424408
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 try text_seg.addSection(self.allocator, .{462 try text_seg.addSection(self.allocator, .{
427 .sectname = makeStaticString("__const"),463 .sectname = makeStaticString("__cstring"),
428 .segname = makeStaticString("__TEXT"),464 .segname = makeStaticString("__TEXT"),
429 .addr = 0,465 .addr = 0,
430 .size = 0,466 .size = 0,
...@@ -432,18 +468,19 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {...@@ -432,18 +468,19 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {
432 .@"align" = 0,468 .@"align" = 0,
433 .reloff = 0,469 .reloff = 0,
434 .nreloc = 0,470 .nreloc = 0,
435 .flags = macho.S_REGULAR,471 .flags = macho.S_CSTRING_LITERALS,
436 .reserved1 = 0,472 .reserved1 = 0,
437 .reserved2 = 0,473 .reserved2 = 0,
438 .reserved3 = 0,474 .reserved3 = 0,
439 });475 });
440 } else if (mem.eql(u8, segname, "__DATA")) {476 },
441 if (!mem.eql(u8, sectname, "__const")) continue;477 macho.S_MOD_INIT_FUNC_POINTERS => {
442 if (self.data_const_section_index != null) continue;478 if (!mem.eql(u8, segname, "__DATA")) continue;
479 if (self.mod_init_func_section_index != null) continue;
443480
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 try data_const_seg.addSection(self.allocator, .{482 try data_const_seg.addSection(self.allocator, .{
446 .sectname = makeStaticString("__const"),483 .sectname = makeStaticString("__mod_init_func"),
447 .segname = makeStaticString("__DATA_CONST"),484 .segname = makeStaticString("__DATA_CONST"),
448 .addr = 0,485 .addr = 0,
449 .size = 0,486 .size = 0,
...@@ -451,183 +488,143 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {...@@ -451,183 +488,143 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {
451 .@"align" = 0,488 .@"align" = 0,
452 .reloff = 0,489 .reloff = 0,
453 .nreloc = 0,490 .nreloc = 0,
454 .flags = macho.S_REGULAR,491 .flags = macho.S_MOD_INIT_FUNC_POINTERS,
455 .reserved1 = 0,492 .reserved1 = 0,
456 .reserved2 = 0,493 .reserved2 = 0,
457 .reserved3 = 0,494 .reserved3 = 0,
458 });495 });
459 }496 },
460 },497 macho.S_MOD_TERM_FUNC_POINTERS => {
461 macho.S_CSTRING_LITERALS => {498 if (!mem.eql(u8, segname, "__DATA")) continue;
462 if (!mem.eql(u8, segname, "__TEXT")) continue;499 if (self.mod_term_func_section_index != null) 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 }
606500
607 // Find ideal section alignment.501 self.mod_term_func_section_index = @intCast(u16, data_const_seg.sections.items.len);
608 for (object_seg.sections.items) |source_sect, id| {502 try data_const_seg.addSection(self.allocator, .{
609 if (self.getMatchingSection(source_sect)) |res| {503 .sectname = makeStaticString("__mod_term_func"),
610 const target_seg = &self.load_commands.items[res.seg].Segment;504 .segname = makeStaticString("__DATA_CONST"),
611 const target_sect = &target_seg.sections.items[res.sect];505 .addr = 0,
612 target_sect.@"align" = math.max(target_sect.@"align", source_sect.@"align");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 }
615602
616 // Update section mappings603 // Find ideal section alignment.
617 for (object_seg.sections.items) |source_sect, id| {604 for (object_seg.sections.items) |source_sect| {
618 const source_sect_id = @intCast(u16, id);605 if (self.getMatchingSection(source_sect)) |res| {
619 if (self.getMatchingSection(source_sect)) |res| {606 const target_seg = &self.load_commands.items[res.seg].Segment;
620 try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect);607 const target_sect = &target_seg.sections.items[res.sect];
621 continue;608 target_sect.@"align" = math.max(target_sect.@"align", source_sect.@"align");
609 }
622 }610 }
623611
624 const segname = parseName(&source_sect.segname);612 // Update section mappings
625 const sectname = parseName(&source_sect.sectname);613 for (object_seg.sections.items) |source_sect, sect_id| {
626 log.debug("section '{s}/{s}' will be unmapped", .{ segname, sectname });614 const source_sect_id = @intCast(u16, sect_id);
627 try self.unhandled_sections.putNoClobber(self.allocator, .{615 if (self.getMatchingSection(source_sect)) |res| {
628 .object_id = object_id,616 try self.mapAndUpdateSections(object_id, source_sect_id, res.seg, res.sect);
629 .source_sect_id = source_sect_id,617 continue;
630 }, 0);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}
633630
...@@ -826,7 +823,10 @@ fn sortSections(self: *Zld) !void {...@@ -826,7 +823,10 @@ fn sortSections(self: *Zld) !void {
826823
827fn allocateTextSegment(self: *Zld) !void {824fn allocateTextSegment(self: *Zld) !void {
828 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;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());
830830
831 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;831 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
832 seg.inner.fileoff = 0;832 seg.inner.fileoff = 0;
...@@ -835,14 +835,14 @@ fn allocateTextSegment(self: *Zld) !void {...@@ -835,14 +835,14 @@ fn allocateTextSegment(self: *Zld) !void {
835 // Set stubs and stub_helper sizes835 // Set stubs and stub_helper sizes
836 const stubs = &seg.sections.items[self.stubs_section_index.?];836 const stubs = &seg.sections.items[self.stubs_section_index.?];
837 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];837 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];
838 stubs.size += nexterns * stubs.reserved2;838 stubs.size += nstubs * stubs.reserved2;
839839
840 const stub_size: u4 = switch (self.arch.?) {840 const stub_size: u4 = switch (self.arch.?) {
841 .x86_64 => 10,841 .x86_64 => 10,
842 .aarch64 => 3 * @sizeOf(u32),842 .aarch64 => 3 * @sizeOf(u32),
843 else => unreachable,843 else => unreachable,
844 };844 };
845 stub_helper.size += nexterns * stub_size;845 stub_helper.size += nstubs * stub_size;
846846
847 var sizeofcmds: u64 = 0;847 var sizeofcmds: u64 = 0;
848 for (self.load_commands.items) |lc| {848 for (self.load_commands.items) |lc| {
...@@ -877,7 +877,10 @@ fn allocateTextSegment(self: *Zld) !void {...@@ -877,7 +877,10 @@ fn allocateTextSegment(self: *Zld) !void {
877877
878fn allocateDataConstSegment(self: *Zld) !void {878fn allocateDataConstSegment(self: *Zld) !void {
879 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;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());
881884
882 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;885 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
883 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;886 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
...@@ -888,14 +891,17 @@ fn allocateDataConstSegment(self: *Zld) !void {...@@ -888,14 +891,17 @@ fn allocateDataConstSegment(self: *Zld) !void {
888 // TODO this will require scanning the relocations at least one to work out891 // TODO this will require scanning the relocations at least one to work out
889 // the exact amount of local GOT indirections. For the time being, set some892 // the exact amount of local GOT indirections. For the time being, set some
890 // default value.893 // default value.
891 got.size += (max_local_got_indirections + nonlazy) * @sizeOf(u64);894 got.size += (max_local_got_indirections + nexterns) * @sizeOf(u64);
892895
893 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);896 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
894}897}
895898
896fn allocateDataSegment(self: *Zld) !void {899fn allocateDataSegment(self: *Zld) !void {
897 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;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());
899905
900 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;906 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
901 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;907 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
...@@ -904,8 +910,8 @@ fn allocateDataSegment(self: *Zld) !void {...@@ -904,8 +910,8 @@ fn allocateDataSegment(self: *Zld) !void {
904 // Set la_symbol_ptr and data size910 // Set la_symbol_ptr and data size
905 const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?];911 const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?];
906 const data = &seg.sections.items[self.data_section_index.?];912 const data = &seg.sections.items[self.data_section_index.?];
907 la_symbol_ptr.size += lazy * @sizeOf(u64);913 la_symbol_ptr.size += nstubs * @sizeOf(u64);
908 data.size += @sizeOf(u64); // TODO when do we need more?914 data.size += @sizeOf(u64); // We need at least 8bytes for address of dyld_stub_binder
909915
910 try self.allocateSegment(self.data_segment_cmd_index.?, 0);916 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
911}917}
...@@ -1303,7 +1309,13 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1303,7 +1309,13 @@ fn resolveSymbols(self: *Zld) !void {
1303 while (self.undefs.items().len > 0) {1309 while (self.undefs.items().len > 0) {
1304 const entry = self.undefs.pop();1310 const entry = self.undefs.pop();
1305 try self.externs.putNoClobber(self.allocator, entry.key, .{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 .file = 0,1319 .file = 0,
1308 });1320 });
1309 }1321 }
...@@ -1316,6 +1328,19 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1316,6 +1328,19 @@ fn resolveSymbols(self: *Zld) !void {
13161328
1317 return error.UndefinedSymbolReference;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}
13201345
1321fn doRelocs(self: *Zld) !void {1346fn doRelocs(self: *Zld) !void {
...@@ -1879,10 +1904,33 @@ fn doRelocs(self: *Zld) !void {...@@ -1879,10 +1904,33 @@ fn doRelocs(self: *Zld) !void {
1879fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 {1904fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 {
1880 const object = self.objects.items[object_id];1905 const object = self.objects.items[object_id];
1881 const seg = object.load_commands.items[object.segment_cmd_index.?].Segment;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 const target_addr = blk: {1930 const target_addr = blk: {
1883 if (rel.r_extern == 1) {1931 if (rel.r_extern == 1) {
1884 const sym = object.symtab.items[rel.r_symbolnum];1932 const sym = object.symtab.items[rel.r_symbolnum];
1885 if (isLocal(&sym) or isExport(&sym)) {1933 if (sym.isSect()) {
1886 // Relocate using section offsets only.1934 // Relocate using section offsets only.
1887 const target_mapping = self.mappings.get(.{1935 const target_mapping = self.mappings.get(.{
1888 .object_id = object_id,1936 .object_id = object_id,
...@@ -1894,30 +1942,13 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64...@@ -1894,30 +1942,13 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
1894 const target_sect_addr = target_sect.addr + target_mapping.offset;1942 const target_sect_addr = target_sect.addr + target_mapping.offset;
1895 log.debug(" | symbol local to object", .{});1943 log.debug(" | symbol local to object", .{});
1896 break :blk target_sect_addr + sym.n_value - source_sect.addr;1944 break :blk target_sect_addr + sym.n_value - source_sect.addr;
1897 } else if (isImport(&sym)) {1945 } else if (sym.isUndf()) {
1898 // Relocate to either the artifact's local symbol, or an import from1946 // Relocate to either the global symbol, or an import from
1899 // shared library.1947 // shared library.
1900 const sym_name = object.getString(sym.n_strx);1948 const sym_name = object.getString(sym.n_strx);
1901 if (self.locals.get(sym_name)) |locs| {1949 if (self.globals.get(sym_name)) |glob| {
1902 var n_value: ?u64 = null;1950 break :blk glob.inner.n_value;
1903 for (locs.items) |loc| {1951 } else if (self.externs.getEntry(sym_name)) |ext| {
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| {
1921 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1952 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1922 const stubs = segment.sections.items[self.stubs_section_index.?];1953 const stubs = segment.sections.items[self.stubs_section_index.?];
1923 break :blk stubs.addr + ext.index * stubs.reserved2;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,7 +1959,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
1928 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {1959 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1929 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;1960 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1930 const tlv = segment.sections.items[self.tlv_section_index.?];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 } else {1963 } else {
1933 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});1964 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1934 return error.FailedToResolveRelocationTarget;1965 return error.FailedToResolveRelocationTarget;
...@@ -1951,6 +1982,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64...@@ -1951,6 +1982,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
1951 break :blk target_sect.addr + target_mapping.offset;1982 break :blk target_sect.addr + target_mapping.offset;
1952 }1983 }
1953 };1984 };
1985
1954 return target_addr;1986 return target_addr;
1955}1987}
19561988