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) = .{},
7878externs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
7979strtab: std.ArrayListUnmanaged(u8) = .{},
8080
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) = .{},
81threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
82rebases: std.ArrayListUnmanaged(Pointer) = .{},
83got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{},
8984
9085stub_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 {
279274 try self.populateMetadata();
280275 try self.parseInputFiles(files);
281276 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();
288283 // try self.writeStubHelperCommon();
289284 // try self.doRelocs();
290285 // try self.flush();
......@@ -403,28 +398,69 @@ fn mapAndUpdateSections(
403398 target_sect.size = offset + size;
404399}
405400
406fn 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;
401fn 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;
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);
426462 try text_seg.addSection(self.allocator, .{
427 .sectname = makeStaticString("__const"),
463 .sectname = makeStaticString("__cstring"),
428464 .segname = makeStaticString("__TEXT"),
429465 .addr = 0,
430466 .size = 0,
......@@ -432,18 +468,19 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {
432468 .@"align" = 0,
433469 .reloff = 0,
434470 .nreloc = 0,
435 .flags = macho.S_REGULAR,
471 .flags = macho.S_CSTRING_LITERALS,
436472 .reserved1 = 0,
437473 .reserved2 = 0,
438474 .reserved3 = 0,
439475 });
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;
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);
445482 try data_const_seg.addSection(self.allocator, .{
446 .sectname = makeStaticString("__const"),
483 .sectname = makeStaticString("__mod_init_func"),
447484 .segname = makeStaticString("__DATA_CONST"),
448485 .addr = 0,
449486 .size = 0,
......@@ -451,183 +488,143 @@ fn updateMetadata(self: *Zld, object_id: u16) !void {
451488 .@"align" = 0,
452489 .reloff = 0,
453490 .nreloc = 0,
454 .flags = macho.S_REGULAR,
491 .flags = macho.S_MOD_INIT_FUNC_POINTERS,
455492 .reserved1 = 0,
456493 .reserved2 = 0,
457494 .reserved3 = 0,
458495 });
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;
606500
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 }
613601 }
614 }
615602
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 }
622610 }
623611
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 }
631628 }
632629}
633630
......@@ -826,7 +823,10 @@ fn sortSections(self: *Zld) !void {
826823
827824fn allocateTextSegment(self: *Zld) !void {
828825 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
831831 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
832832 seg.inner.fileoff = 0;
......@@ -835,14 +835,14 @@ fn allocateTextSegment(self: *Zld) !void {
835835 // Set stubs and stub_helper sizes
836836 const stubs = &seg.sections.items[self.stubs_section_index.?];
837837 const stub_helper = &seg.sections.items[self.stub_helper_section_index.?];
838 stubs.size += nexterns * stubs.reserved2;
838 stubs.size += nstubs * stubs.reserved2;
839839
840840 const stub_size: u4 = switch (self.arch.?) {
841841 .x86_64 => 10,
842842 .aarch64 => 3 * @sizeOf(u32),
843843 else => unreachable,
844844 };
845 stub_helper.size += nexterns * stub_size;
845 stub_helper.size += nstubs * stub_size;
846846
847847 var sizeofcmds: u64 = 0;
848848 for (self.load_commands.items) |lc| {
......@@ -877,7 +877,10 @@ fn allocateTextSegment(self: *Zld) !void {
877877
878878fn allocateDataConstSegment(self: *Zld) !void {
879879 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
882885 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
883886 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
......@@ -888,14 +891,17 @@ fn allocateDataConstSegment(self: *Zld) !void {
888891 // TODO this will require scanning the relocations at least one to work out
889892 // the exact amount of local GOT indirections. For the time being, set some
890893 // default value.
891 got.size += (max_local_got_indirections + nonlazy) * @sizeOf(u64);
894 got.size += (max_local_got_indirections + nexterns) * @sizeOf(u64);
892895
893896 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
894897}
895898
896899fn allocateDataSegment(self: *Zld) !void {
897900 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
900906 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
901907 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
......@@ -904,8 +910,8 @@ fn allocateDataSegment(self: *Zld) !void {
904910 // Set la_symbol_ptr and data size
905911 const la_symbol_ptr = &seg.sections.items[self.la_symbol_ptr_section_index.?];
906912 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
909915
910916 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
911917}
......@@ -1303,7 +1309,13 @@ fn resolveSymbols(self: *Zld) !void {
13031309 while (self.undefs.items().len > 0) {
13041310 const entry = self.undefs.pop();
13051311 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 },
13071319 .file = 0,
13081320 });
13091321 }
......@@ -1316,6 +1328,19 @@ fn resolveSymbols(self: *Zld) !void {
13161328
13171329 return error.UndefinedSymbolReference;
13181330 }
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 });
13191344}
13201345
13211346fn doRelocs(self: *Zld) !void {
......@@ -1879,10 +1904,33 @@ fn doRelocs(self: *Zld) !void {
18791904fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64 {
18801905 const object = self.objects.items[object_id];
18811906 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
18821930 const target_addr = blk: {
18831931 if (rel.r_extern == 1) {
18841932 const sym = object.symtab.items[rel.r_symbolnum];
1885 if (isLocal(&sym) or isExport(&sym)) {
1933 if (sym.isSect()) {
18861934 // Relocate using section offsets only.
18871935 const target_mapping = self.mappings.get(.{
18881936 .object_id = object_id,
......@@ -1894,30 +1942,13 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
18941942 const target_sect_addr = target_sect.addr + target_mapping.offset;
18951943 log.debug(" | symbol local to object", .{});
18961944 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
18991947 // shared library.
19001948 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| {
19211952 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
19221953 const stubs = segment.sections.items[self.stubs_section_index.?];
19231954 break :blk stubs.addr + ext.index * stubs.reserved2;
......@@ -1928,7 +1959,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
19281959 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
19291960 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
19301961 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;
19321963 } else {
19331964 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
19341965 return error.FailedToResolveRelocationTarget;
......@@ -1951,6 +1982,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, rel: macho.relocation_info) !u64
19511982 break :blk target_sect.addr + target_mapping.offset;
19521983 }
19531984 };
1985
19541986 return target_addr;
19551987}
19561988