authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-23 18:32:43-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-09-23 18:32:43-07:00
logc9413a880be0e5817d31a35c95d4c8f7d1f81eff
treeab1a7b755226b6ce163f069f303397d539202f81
parent8b78df403fe71ffdf8c39361dd30a3c1171a1f1c
parentab8a5bfe83848c0d0ceb7ac08fe7f535783e1605
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17244 from ziglang/elf-vm-mgmt

elf: misc improvements, plus let's actually link against a parsed archive!

6 files changed, 373 insertions(+), 360 deletions(-)

src/link/Elf.zig+330-341
......@@ -373,9 +373,8 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
373373 return null;
374374}
375375
376pub fn allocatedSize(self: *Elf, start: u64) u64 {
377 if (start == 0)
378 return 0;
376fn allocatedSize(self: *Elf, start: u64) u64 {
377 if (start == 0) return 0;
379378 var min_pos: u64 = std.math.maxInt(u64);
380379 if (self.shdr_table_offset) |off| {
381380 if (off > start and off < min_pos) min_pos = off;
......@@ -391,7 +390,17 @@ pub fn allocatedSize(self: *Elf, start: u64) u64 {
391390 return min_pos - start;
392391}
393392
394pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
393fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
394 if (start == 0) return 0;
395 var min_pos: u64 = std.math.maxInt(u64);
396 for (self.phdrs.items) |phdr| {
397 if (phdr.p_vaddr <= start) continue;
398 if (phdr.p_vaddr < min_pos) min_pos = phdr.p_vaddr;
399 }
400 return min_pos - start;
401}
402
403fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
395404 var start: u64 = 0;
396405 while (self.detectAllocCollision(start, object_size)) |item_end| {
397406 start = mem.alignForward(u64, item_end, min_alignment);
......@@ -399,6 +408,113 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u32) u64 {
399408 return start;
400409}
401410
411const AllocateSegmentOpts = struct {
412 addr: u64, // TODO find free VM space
413 size: u64,
414 alignment: u64,
415 flags: u32 = elf.PF_R,
416};
417
418fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory}!u16 {
419 const index = @as(u16, @intCast(self.phdrs.items.len));
420 try self.phdrs.ensureUnusedCapacity(self.base.allocator, 1);
421 const off = self.findFreeSpace(opts.size, opts.alignment);
422 log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
423 index,
424 if (opts.flags & elf.PF_R != 0) @as(u8, 'R') else '_',
425 if (opts.flags & elf.PF_W != 0) @as(u8, 'W') else '_',
426 if (opts.flags & elf.PF_X != 0) @as(u8, 'X') else '_',
427 off,
428 off + opts.size,
429 opts.addr,
430 opts.addr + opts.size,
431 });
432 self.phdrs.appendAssumeCapacity(.{
433 .p_type = elf.PT_LOAD,
434 .p_offset = off,
435 .p_filesz = opts.size,
436 .p_vaddr = opts.addr,
437 .p_paddr = opts.addr,
438 .p_memsz = opts.size,
439 .p_align = opts.alignment,
440 .p_flags = opts.flags,
441 });
442 self.phdr_table_dirty = true;
443 return index;
444}
445
446const AllocateAllocSectionOpts = struct {
447 name: [:0]const u8,
448 phdr_index: u16,
449 alignment: u16 = 1,
450 flags: u16 = elf.SHF_ALLOC,
451 type: u32 = elf.SHT_PROGBITS,
452};
453
454fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{OutOfMemory}!u16 {
455 const gpa = self.base.allocator;
456 const phdr = &self.phdrs.items[opts.phdr_index];
457 const index = @as(u16, @intCast(self.shdrs.items.len));
458 try self.shdrs.ensureUnusedCapacity(gpa, 1);
459 const sh_name = try self.shstrtab.insert(gpa, opts.name);
460 try self.phdr_to_shdr_table.putNoClobber(gpa, index, opts.phdr_index);
461 log.debug("allocating '{s}' in phdr({d}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{
462 opts.name,
463 opts.phdr_index,
464 phdr.p_offset,
465 phdr.p_offset + phdr.p_filesz,
466 phdr.p_vaddr,
467 phdr.p_vaddr + phdr.p_memsz,
468 });
469 self.shdrs.appendAssumeCapacity(.{
470 .sh_name = sh_name,
471 .sh_type = opts.type,
472 .sh_flags = opts.flags,
473 .sh_addr = phdr.p_vaddr,
474 .sh_offset = phdr.p_offset,
475 .sh_size = phdr.p_filesz,
476 .sh_link = 0,
477 .sh_info = 0,
478 .sh_addralign = opts.alignment,
479 .sh_entsize = 0,
480 });
481 self.shdr_table_dirty = true;
482 return index;
483}
484
485const AllocateNonAllocSectionOpts = struct {
486 name: [:0]const u8,
487 size: u64,
488 alignment: u16 = 1,
489 flags: u32 = 0,
490 type: u32 = elf.SHT_PROGBITS,
491 link: u32 = 0,
492 info: u32 = 0,
493 entsize: u64 = 0,
494};
495
496fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{OutOfMemory}!u16 {
497 const index = @as(u16, @intCast(self.shdrs.items.len));
498 try self.shdrs.ensureUnusedCapacity(self.base.allocator, 1);
499 const sh_name = try self.shstrtab.insert(self.base.allocator, opts.name);
500 const off = self.findFreeSpace(opts.size, opts.alignment);
501 log.debug("allocating '{s}' from 0x{x} to 0x{x} ", .{ opts.name, off, off + opts.size });
502 self.shdrs.appendAssumeCapacity(.{
503 .sh_name = sh_name,
504 .sh_type = opts.type,
505 .sh_flags = opts.flags,
506 .sh_addr = 0,
507 .sh_offset = off,
508 .sh_size = opts.size,
509 .sh_link = opts.link,
510 .sh_info = opts.info,
511 .sh_addralign = opts.alignment,
512 .sh_entsize = opts.entsize,
513 });
514 self.shdr_table_dirty = true;
515 return index;
516}
517
402518pub fn populateMissingMetadata(self: *Elf) !void {
403519 const gpa = self.base.allocator;
404520 const small_ptr = switch (self.ptr_width) {
......@@ -429,7 +545,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
429545
430546 if (self.phdr_table_load_index == null) {
431547 self.phdr_table_load_index = @intCast(self.phdrs.items.len);
432 // TODO Same as for GOT
433548 try self.phdrs.append(gpa, .{
434549 .p_type = elf.PT_LOAD,
435550 .p_offset = 0,
......@@ -444,401 +559,200 @@ pub fn populateMissingMetadata(self: *Elf) !void {
444559 }
445560
446561 if (self.phdr_load_re_index == null) {
447 self.phdr_load_re_index = @intCast(self.phdrs.items.len);
448 const file_size = self.base.options.program_code_size_hint;
449 const p_align = self.page_size;
450 const off = self.findFreeSpace(file_size, p_align);
451 log.debug("found PT_LOAD RE free space 0x{x} to 0x{x}", .{ off, off + file_size });
452 const entry_addr = self.defaultEntryAddress();
453 try self.phdrs.append(gpa, .{
454 .p_type = elf.PT_LOAD,
455 .p_offset = off,
456 .p_filesz = file_size,
457 .p_vaddr = entry_addr,
458 .p_paddr = entry_addr,
459 .p_memsz = file_size,
460 .p_align = p_align,
461 .p_flags = elf.PF_X | elf.PF_R | elf.PF_W,
562 self.phdr_load_re_index = try self.allocateSegment(.{
563 .addr = self.defaultEntryAddress(),
564 .size = self.base.options.program_code_size_hint,
565 .alignment = self.page_size,
566 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
462567 });
463568 self.entry_addr = null;
464 self.phdr_table_dirty = true;
465569 }
466570
467571 if (self.phdr_got_index == null) {
468 self.phdr_got_index = @intCast(self.phdrs.items.len);
469 const file_size = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
470 // We really only need ptr alignment but since we are using PROGBITS, linux requires
471 // page align.
472 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
473 const off = self.findFreeSpace(file_size, p_align);
474 log.debug("found PT_LOAD GOT free space 0x{x} to 0x{x}", .{ off, off + file_size });
475572 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
476573 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
477574 // else in virtual memory.
478 const got_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
479 try self.phdrs.append(gpa, .{
480 .p_type = elf.PT_LOAD,
481 .p_offset = off,
482 .p_filesz = file_size,
483 .p_vaddr = got_addr,
484 .p_paddr = got_addr,
485 .p_memsz = file_size,
486 .p_align = p_align,
487 .p_flags = elf.PF_R | elf.PF_W,
575 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x4000000 else 0x8000;
576 // We really only need ptr alignment but since we are using PROGBITS, linux requires
577 // page align.
578 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
579 self.phdr_got_index = try self.allocateSegment(.{
580 .addr = addr,
581 .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint,
582 .alignment = alignment,
583 .flags = elf.PF_R | elf.PF_W,
488584 });
489 self.phdr_table_dirty = true;
490585 }
491586
492587 if (self.phdr_load_ro_index == null) {
493 self.phdr_load_ro_index = @intCast(self.phdrs.items.len);
494 // TODO Find a hint about how much data need to be in rodata ?
495 const file_size = 1024;
496 // Same reason as for GOT
497 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
498 const off = self.findFreeSpace(file_size, p_align);
499 log.debug("found PT_LOAD RO free space 0x{x} to 0x{x}", .{ off, off + file_size });
500588 // TODO Same as for GOT
501 const rodata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
502 try self.phdrs.append(gpa, .{
503 .p_type = elf.PT_LOAD,
504 .p_offset = off,
505 .p_filesz = file_size,
506 .p_vaddr = rodata_addr,
507 .p_paddr = rodata_addr,
508 .p_memsz = file_size,
509 .p_align = p_align,
510 .p_flags = elf.PF_R | elf.PF_W,
589 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0xc000000 else 0xa000;
590 // Same reason as for GOT
591 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
592 self.phdr_load_ro_index = try self.allocateSegment(.{
593 .addr = addr,
594 .size = 1024,
595 .alignment = alignment,
596 .flags = elf.PF_R | elf.PF_W,
511597 });
512 self.phdr_table_dirty = true;
513598 }
514599
515600 if (self.phdr_load_rw_index == null) {
516 self.phdr_load_rw_index = @intCast(self.phdrs.items.len);
517 // TODO Find a hint about how much data need to be in data ?
518 const file_size = 1024;
519 // Same reason as for GOT
520 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
521 const off = self.findFreeSpace(file_size, p_align);
522 log.debug("found PT_LOAD RW free space 0x{x} to 0x{x}", .{ off, off + file_size });
523601 // TODO Same as for GOT
524 const rwdata_addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
525 try self.phdrs.append(gpa, .{
526 .p_type = elf.PT_LOAD,
527 .p_offset = off,
528 .p_filesz = file_size,
529 .p_vaddr = rwdata_addr,
530 .p_paddr = rwdata_addr,
531 .p_memsz = file_size,
532 .p_align = p_align,
533 .p_flags = elf.PF_R | elf.PF_W,
602 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x10000000 else 0xc000;
603 // Same reason as for GOT
604 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
605 self.phdr_load_rw_index = try self.allocateSegment(.{
606 .addr = addr,
607 .size = 1024,
608 .alignment = alignment,
609 .flags = elf.PF_R | elf.PF_W,
534610 });
535 self.phdr_table_dirty = true;
536611 }
537612
538613 if (self.phdr_load_zerofill_index == null) {
539 self.phdr_load_zerofill_index = @intCast(self.phdrs.items.len);
540 const p_align = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
541 const off = self.phdrs.items[self.phdr_load_rw_index.?].p_offset;
542 log.debug("found PT_LOAD zerofill free space 0x{x} to 0x{x}", .{ off, off });
543614 // TODO Same as for GOT
544 const addr: u32 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;
545 try self.phdrs.append(gpa, .{
546 .p_type = elf.PT_LOAD,
547 .p_offset = off,
548 .p_filesz = 0,
549 .p_vaddr = addr,
550 .p_paddr = addr,
551 .p_memsz = 0,
552 .p_align = p_align,
553 .p_flags = elf.PF_R | elf.PF_W,
615 const addr: u64 = if (self.base.options.target.ptrBitWidth() >= 32) 0x14000000 else 0xf000;
616 const alignment = if (self.base.options.target.os.tag == .linux) self.page_size else @as(u16, ptr_size);
617 self.phdr_load_zerofill_index = try self.allocateSegment(.{
618 .addr = addr,
619 .size = 0,
620 .alignment = alignment,
621 .flags = elf.PF_R | elf.PF_W,
554622 });
555 self.phdr_table_dirty = true;
623 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];
624 phdr.p_offset = self.phdrs.items[self.phdr_load_rw_index.?].p_offset; // .bss overlaps .data
556625 }
557626
558627 if (self.shstrtab_section_index == null) {
559 self.shstrtab_section_index = @intCast(self.shdrs.items.len);
560628 assert(self.shstrtab.buffer.items.len == 0);
561629 try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0
562 const off = self.findFreeSpace(self.shstrtab.buffer.items.len, 1);
563 log.debug("found .shstrtab free space 0x{x} to 0x{x}", .{ off, off + self.shstrtab.buffer.items.len });
564 try self.shdrs.append(gpa, .{
565 .sh_name = try self.shstrtab.insert(gpa, ".shstrtab"),
566 .sh_type = elf.SHT_STRTAB,
567 .sh_flags = 0,
568 .sh_addr = 0,
569 .sh_offset = off,
570 .sh_size = self.shstrtab.buffer.items.len,
571 .sh_link = 0,
572 .sh_info = 0,
573 .sh_addralign = 1,
574 .sh_entsize = 0,
630 self.shstrtab_section_index = try self.allocateNonAllocSection(.{
631 .name = ".shstrtab",
632 .size = @intCast(self.shstrtab.buffer.items.len),
633 .type = elf.SHT_STRTAB,
575634 });
576635 self.shstrtab_dirty = true;
577 self.shdr_table_dirty = true;
578636 }
579637
580638 if (self.strtab_section_index == null) {
581 self.strtab_section_index = @intCast(self.shdrs.items.len);
582639 assert(self.strtab.buffer.items.len == 0);
583640 try self.strtab.buffer.append(gpa, 0); // need a 0 at position 0
584 const off = self.findFreeSpace(self.strtab.buffer.items.len, 1);
585 log.debug("found .strtab free space 0x{x} to 0x{x}", .{ off, off + self.strtab.buffer.items.len });
586 try self.shdrs.append(gpa, .{
587 .sh_name = try self.shstrtab.insert(gpa, ".strtab"),
588 .sh_type = elf.SHT_STRTAB,
589 .sh_flags = 0,
590 .sh_addr = 0,
591 .sh_offset = off,
592 .sh_size = self.strtab.buffer.items.len,
593 .sh_link = 0,
594 .sh_info = 0,
595 .sh_addralign = 1,
596 .sh_entsize = 0,
641 self.strtab_section_index = try self.allocateNonAllocSection(.{
642 .name = ".strtab",
643 .size = @intCast(self.strtab.buffer.items.len),
644 .type = elf.SHT_STRTAB,
597645 });
598646 self.strtab_dirty = true;
599 self.shdr_table_dirty = true;
600647 }
601648
602649 if (self.text_section_index == null) {
603 self.text_section_index = @intCast(self.shdrs.items.len);
604 const phdr = &self.phdrs.items[self.phdr_load_re_index.?];
605 try self.shdrs.append(gpa, .{
606 .sh_name = try self.shstrtab.insert(gpa, ".text"),
607 .sh_type = elf.SHT_PROGBITS,
608 .sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
609 .sh_addr = phdr.p_vaddr,
610 .sh_offset = phdr.p_offset,
611 .sh_size = phdr.p_filesz,
612 .sh_link = 0,
613 .sh_info = 0,
614 .sh_addralign = 1,
615 .sh_entsize = 0,
650 self.text_section_index = try self.allocateAllocSection(.{
651 .name = ".text",
652 .phdr_index = self.phdr_load_re_index.?,
653 .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
616654 });
617 try self.phdr_to_shdr_table.putNoClobber(gpa, self.text_section_index.?, self.phdr_load_re_index.?);
618655 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.text_section_index.?, .{});
619 self.shdr_table_dirty = true;
620656 }
621657
622658 if (self.got_section_index == null) {
623 self.got_section_index = @intCast(self.shdrs.items.len);
624 const phdr = &self.phdrs.items[self.phdr_got_index.?];
625 try self.shdrs.append(gpa, .{
626 .sh_name = try self.shstrtab.insert(gpa, ".got"),
627 .sh_type = elf.SHT_PROGBITS,
628 .sh_flags = elf.SHF_ALLOC,
629 .sh_addr = phdr.p_vaddr,
630 .sh_offset = phdr.p_offset,
631 .sh_size = phdr.p_filesz,
632 .sh_link = 0,
633 .sh_info = 0,
634 .sh_addralign = @as(u16, ptr_size),
635 .sh_entsize = 0,
659 self.got_section_index = try self.allocateAllocSection(.{
660 .name = ".got",
661 .phdr_index = self.phdr_got_index.?,
662 .alignment = ptr_size,
636663 });
637 try self.phdr_to_shdr_table.putNoClobber(gpa, self.got_section_index.?, self.phdr_got_index.?);
638 self.shdr_table_dirty = true;
639664 }
640665
641666 if (self.rodata_section_index == null) {
642 self.rodata_section_index = @intCast(self.shdrs.items.len);
643 const phdr = &self.phdrs.items[self.phdr_load_ro_index.?];
644 try self.shdrs.append(gpa, .{
645 .sh_name = try self.shstrtab.insert(gpa, ".rodata"),
646 .sh_type = elf.SHT_PROGBITS,
647 .sh_flags = elf.SHF_ALLOC,
648 .sh_addr = phdr.p_vaddr,
649 .sh_offset = phdr.p_offset,
650 .sh_size = phdr.p_filesz,
651 .sh_link = 0,
652 .sh_info = 0,
653 .sh_addralign = 1,
654 .sh_entsize = 0,
667 self.rodata_section_index = try self.allocateAllocSection(.{
668 .name = ".rodata",
669 .phdr_index = self.phdr_load_ro_index.?,
655670 });
656 try self.phdr_to_shdr_table.putNoClobber(gpa, self.rodata_section_index.?, self.phdr_load_ro_index.?);
657671 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.rodata_section_index.?, .{});
658 self.shdr_table_dirty = true;
659672 }
660673
661674 if (self.data_section_index == null) {
662 self.data_section_index = @intCast(self.shdrs.items.len);
663 const phdr = &self.phdrs.items[self.phdr_load_rw_index.?];
664 try self.shdrs.append(gpa, .{
665 .sh_name = try self.shstrtab.insert(gpa, ".data"),
666 .sh_type = elf.SHT_PROGBITS,
667 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
668 .sh_addr = phdr.p_vaddr,
669 .sh_offset = phdr.p_offset,
670 .sh_size = phdr.p_filesz,
671 .sh_link = 0,
672 .sh_info = 0,
673 .sh_addralign = @as(u16, ptr_size),
674 .sh_entsize = 0,
675 self.data_section_index = try self.allocateAllocSection(.{
676 .name = ".data",
677 .phdr_index = self.phdr_load_rw_index.?,
678 .alignment = ptr_size,
679 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
675680 });
676 try self.phdr_to_shdr_table.putNoClobber(gpa, self.data_section_index.?, self.phdr_load_rw_index.?);
677681 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.data_section_index.?, .{});
678 self.shdr_table_dirty = true;
679682 }
680683
681684 if (self.bss_section_index == null) {
682 self.bss_section_index = @intCast(self.shdrs.items.len);
683 const phdr = &self.phdrs.items[self.phdr_load_zerofill_index.?];
684 try self.shdrs.append(gpa, .{
685 .sh_name = try self.shstrtab.insert(gpa, ".bss"),
686 .sh_type = elf.SHT_NOBITS,
687 .sh_flags = elf.SHF_WRITE | elf.SHF_ALLOC,
688 .sh_addr = phdr.p_vaddr,
689 .sh_offset = phdr.p_offset,
690 .sh_size = phdr.p_filesz,
691 .sh_link = 0,
692 .sh_info = 0,
693 .sh_addralign = @as(u16, ptr_size),
694 .sh_entsize = 0,
685 self.bss_section_index = try self.allocateAllocSection(.{
686 .name = ".bss",
687 .phdr_index = self.phdr_load_zerofill_index.?,
688 .alignment = ptr_size,
689 .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
690 .type = elf.SHT_NOBITS,
695691 });
696 try self.phdr_to_shdr_table.putNoClobber(gpa, self.bss_section_index.?, self.phdr_load_zerofill_index.?);
697692 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{});
698 self.shdr_table_dirty = true;
699693 }
700694
701695 if (self.symtab_section_index == null) {
702 self.symtab_section_index = @intCast(self.shdrs.items.len);
703696 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
704697 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
705 const file_size = self.base.options.symbol_count_hint * each_size;
706 const off = self.findFreeSpace(file_size, min_align);
707 log.debug("found symtab free space 0x{x} to 0x{x}", .{ off, off + file_size });
708 try self.shdrs.append(gpa, .{
709 .sh_name = try self.shstrtab.insert(gpa, ".symtab"),
710 .sh_type = elf.SHT_SYMTAB,
711 .sh_flags = 0,
712 .sh_addr = 0,
713 .sh_offset = off,
714 .sh_size = file_size,
715 // The section header index of the associated string table.
716 .sh_link = self.strtab_section_index.?,
717 .sh_info = @intCast(self.symbols.items.len),
718 .sh_addralign = min_align,
719 .sh_entsize = each_size,
698 self.symtab_section_index = try self.allocateNonAllocSection(.{
699 .name = ".symtab",
700 .size = self.base.options.symbol_count_hint * each_size,
701 .alignment = min_align,
702 .type = elf.SHT_SYMTAB,
703 .link = self.strtab_section_index.?, // Index of associated string table
704 .info = @intCast(self.symbols.items.len),
705 .entsize = each_size,
720706 });
721707 self.shdr_table_dirty = true;
722708 }
723709
724710 if (self.dwarf) |*dw| {
725711 if (self.debug_str_section_index == null) {
726 self.debug_str_section_index = @intCast(self.shdrs.items.len);
727712 assert(dw.strtab.buffer.items.len == 0);
728713 try dw.strtab.buffer.append(gpa, 0);
729 try self.shdrs.append(gpa, .{
730 .sh_name = try self.shstrtab.insert(gpa, ".debug_str"),
731 .sh_type = elf.SHT_PROGBITS,
732 .sh_flags = elf.SHF_MERGE | elf.SHF_STRINGS,
733 .sh_addr = 0,
734 .sh_offset = 0,
735 .sh_size = 0,
736 .sh_link = 0,
737 .sh_info = 0,
738 .sh_addralign = 1,
739 .sh_entsize = 1,
714 self.debug_str_section_index = try self.allocateNonAllocSection(.{
715 .name = ".debug_str",
716 .size = @intCast(dw.strtab.buffer.items.len),
717 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
718 .entsize = 1,
740719 });
741720 self.debug_strtab_dirty = true;
742 self.shdr_table_dirty = true;
743721 }
744722
745723 if (self.debug_info_section_index == null) {
746 self.debug_info_section_index = @intCast(self.shdrs.items.len);
747 const file_size_hint = 200;
748 const p_align = 1;
749 const off = self.findFreeSpace(file_size_hint, p_align);
750 log.debug("found .debug_info free space 0x{x} to 0x{x}", .{
751 off,
752 off + file_size_hint,
753 });
754 try self.shdrs.append(gpa, .{
755 .sh_name = try self.shstrtab.insert(gpa, ".debug_info"),
756 .sh_type = elf.SHT_PROGBITS,
757 .sh_flags = 0,
758 .sh_addr = 0,
759 .sh_offset = off,
760 .sh_size = file_size_hint,
761 .sh_link = 0,
762 .sh_info = 0,
763 .sh_addralign = p_align,
764 .sh_entsize = 0,
724 self.debug_info_section_index = try self.allocateNonAllocSection(.{
725 .name = ".debug_info",
726 .size = 200,
727 .alignment = 1,
765728 });
766 self.shdr_table_dirty = true;
767729 self.debug_info_header_dirty = true;
768730 }
769731
770732 if (self.debug_abbrev_section_index == null) {
771 self.debug_abbrev_section_index = @intCast(self.shdrs.items.len);
772 const file_size_hint = 128;
773 const p_align = 1;
774 const off = self.findFreeSpace(file_size_hint, p_align);
775 log.debug("found .debug_abbrev free space 0x{x} to 0x{x}", .{
776 off,
777 off + file_size_hint,
733 self.debug_abbrev_section_index = try self.allocateNonAllocSection(.{
734 .name = ".debug_abbrev",
735 .size = 128,
736 .alignment = 1,
778737 });
779 try self.shdrs.append(gpa, .{
780 .sh_name = try self.shstrtab.insert(gpa, ".debug_abbrev"),
781 .sh_type = elf.SHT_PROGBITS,
782 .sh_flags = 0,
783 .sh_addr = 0,
784 .sh_offset = off,
785 .sh_size = file_size_hint,
786 .sh_link = 0,
787 .sh_info = 0,
788 .sh_addralign = p_align,
789 .sh_entsize = 0,
790 });
791 self.shdr_table_dirty = true;
792738 self.debug_abbrev_section_dirty = true;
793739 }
794740
795741 if (self.debug_aranges_section_index == null) {
796 self.debug_aranges_section_index = @intCast(self.shdrs.items.len);
797 const file_size_hint = 160;
798 const p_align = 16;
799 const off = self.findFreeSpace(file_size_hint, p_align);
800 log.debug("found .debug_aranges free space 0x{x} to 0x{x}", .{
801 off,
802 off + file_size_hint,
803 });
804 try self.shdrs.append(gpa, .{
805 .sh_name = try self.shstrtab.insert(gpa, ".debug_aranges"),
806 .sh_type = elf.SHT_PROGBITS,
807 .sh_flags = 0,
808 .sh_addr = 0,
809 .sh_offset = off,
810 .sh_size = file_size_hint,
811 .sh_link = 0,
812 .sh_info = 0,
813 .sh_addralign = p_align,
814 .sh_entsize = 0,
742 self.debug_aranges_section_index = try self.allocateNonAllocSection(.{
743 .name = ".debug_aranges",
744 .size = 160,
745 .alignment = 16,
815746 });
816 self.shdr_table_dirty = true;
817747 self.debug_aranges_section_dirty = true;
818748 }
819749
820750 if (self.debug_line_section_index == null) {
821 self.debug_line_section_index = @intCast(self.shdrs.items.len);
822 const file_size_hint = 250;
823 const p_align = 1;
824 const off = self.findFreeSpace(file_size_hint, p_align);
825 log.debug("found .debug_line free space 0x{x} to 0x{x}", .{
826 off,
827 off + file_size_hint,
751 self.debug_line_section_index = try self.allocateNonAllocSection(.{
752 .name = ".debug_line",
753 .size = 250,
754 .alignment = 1,
828755 });
829 try self.shdrs.append(gpa, .{
830 .sh_name = try self.shstrtab.insert(gpa, ".debug_line"),
831 .sh_type = elf.SHT_PROGBITS,
832 .sh_flags = 0,
833 .sh_addr = 0,
834 .sh_offset = off,
835 .sh_size = file_size_hint,
836 .sh_link = 0,
837 .sh_info = 0,
838 .sh_addralign = p_align,
839 .sh_entsize = 0,
840 });
841 self.shdr_table_dirty = true;
842756 self.debug_line_header_dirty = true;
843757 }
844758 }
......@@ -907,7 +821,6 @@ pub fn populateMissingMetadata(self: *Elf) !void {
907821}
908822
909823pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
910 // TODO Also detect virtual address collisions.
911824 const shdr = &self.shdrs.items[shdr_index];
912825 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
913826 const phdr = &self.phdrs.items[phdr_index];
......@@ -922,8 +835,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
922835 } else shdr.sh_size;
923836 shdr.sh_size = 0;
924837
925 log.debug("new '{?s}' file offset 0x{x} to 0x{x}", .{
926 self.shstrtab.get(shdr.sh_name),
838 log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
839 self.shstrtab.getAssumeExists(shdr.sh_name),
927840 new_offset,
928841 new_offset + existing_size,
929842 });
......@@ -935,6 +848,9 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
935848 phdr.p_offset = new_offset;
936849 }
937850
851 const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
852 assert(needed_size <= mem_capacity); // TODO grow section in virtual memory
853
938854 shdr.sh_size = needed_size;
939855 phdr.p_memsz = needed_size;
940856
......@@ -1160,7 +1076,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11601076 for (self.file(index).?.zig_module.atoms.keys()) |atom_index| {
11611077 const atom_ptr = self.atom(atom_index).?;
11621078 if (!atom_ptr.alive) continue;
1163 const shdr = &self.shdrs.items[atom_ptr.output_section_index];
1079 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
11641080 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
11651081 const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
11661082 const code = try gpa.alloc(u8, size);
......@@ -1190,6 +1106,16 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
11901106 try self.updateSymtabSize();
11911107 try self.writeSymtab();
11921108
1109 // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't
1110 // get mapped by the loader
1111 if (self.data_section_index) |data_shndx| blk: {
1112 const bss_shndx = self.bss_section_index orelse break :blk;
1113 const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?;
1114 const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?;
1115 self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset;
1116 self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset;
1117 }
1118
11931119 // Dump the state for easy debugging.
11941120 // State can be dumped via `--debug-log link_state`.
11951121 if (build_options.enable_logging) {
......@@ -1567,6 +1493,7 @@ fn resolveSymbols(self: *Elf) error{Overflow}!void {
15671493/// This routine will prune unneeded objects extracted from archives and
15681494/// unneeded shared objects.
15691495fn markLive(self: *Elf) void {
1496 if (self.zig_module_index) |index| self.file(index).?.markLive(self);
15701497 for (self.objects.items) |index| {
15711498 const file_ptr = self.file(index).?;
15721499 if (file_ptr.isAlive()) file_ptr.markLive(self);
......@@ -1689,7 +1616,7 @@ fn writeObjects(self: *Elf) !void {
16891616 const atom_ptr = self.atom(atom_index) orelse continue;
16901617 if (!atom_ptr.alive) continue;
16911618
1692 const shdr = &self.shdrs.items[atom_ptr.output_section_index];
1619 const shdr = &self.shdrs.items[atom_ptr.outputShndx().?];
16931620 if (shdr.sh_type == elf.SHT_NOBITS) continue;
16941621 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; // TODO we don't yet know how to handle non-alloc sections
16951622
......@@ -2563,15 +2490,15 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
25632490 }
25642491}
25652492
2566pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !Symbol.Index {
2493pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymbol) !Symbol.Index {
25672494 const mod = self.base.options.module.?;
2568 const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl(mod));
2495 const gop = try self.lazy_syms.getOrPut(self.base.allocator, lazy_sym.getDecl(mod));
25692496 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
25702497 if (!gop.found_existing) gop.value_ptr.* = .{};
25712498 const metadata: struct {
25722499 symbol_index: *Symbol.Index,
25732500 state: *LazySymbolMetadata.State,
2574 } = switch (sym.kind) {
2501 } = switch (lazy_sym.kind) {
25752502 .code => .{
25762503 .symbol_index = &gop.value_ptr.text_symbol_index,
25772504 .state = &gop.value_ptr.text_state,
......@@ -2583,17 +2510,14 @@ pub fn getOrCreateMetadataForLazySymbol(self: *Elf, sym: link.File.LazySymbol) !
25832510 };
25842511 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
25852512 switch (metadata.state.*) {
2586 .unused => metadata.symbol_index.* = try zig_module.addAtom(switch (sym.kind) {
2587 .code => self.text_section_index.?,
2588 .const_data => self.rodata_section_index.?,
2589 }, self),
2513 .unused => metadata.symbol_index.* = try zig_module.addAtom(self),
25902514 .pending_flush => return metadata.symbol_index.*,
25912515 .flushed => {},
25922516 }
25932517 metadata.state.* = .pending_flush;
25942518 const symbol_index = metadata.symbol_index.*;
25952519 // anyerror needs to be deferred until flushModule
2596 if (sym.getDecl(mod) != .none) try self.updateLazySymbol(sym, symbol_index);
2520 if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(lazy_sym, symbol_index);
25972521 return symbol_index;
25982522}
25992523
......@@ -2602,35 +2526,37 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy
26022526 if (!gop.found_existing) {
26032527 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
26042528 gop.value_ptr.* = .{
2605 .symbol_index = try zig_module.addAtom(self.getDeclShdrIndex(decl_index), self),
2529 .symbol_index = try zig_module.addAtom(self),
26062530 .exports = .{},
26072531 };
26082532 }
26092533 return gop.value_ptr.symbol_index;
26102534}
26112535
2612fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index) u16 {
2536fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 {
26132537 const mod = self.base.options.module.?;
26142538 const decl = mod.declPtr(decl_index);
2615 const ty = decl.ty;
2616 const zig_ty = ty.zigTypeTag(mod);
2617 const val = decl.val;
2618 const shdr_index: u16 = blk: {
2619 if (val.isUndefDeep(mod)) {
2620 // TODO in release-fast and release-small, we should put undef in .bss
2621 break :blk self.data_section_index.?;
2622 }
2623
2624 switch (zig_ty) {
2625 // TODO: what if this is a function pointer?
2626 .Fn => break :blk self.text_section_index.?,
2627 else => {
2628 if (val.getVariable(mod)) |_| {
2629 break :blk self.data_section_index.?;
2539 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
2540 // TODO: what if this is a function pointer?
2541 .Fn => self.text_section_index.?,
2542 else => blk: {
2543 if (decl.getOwnedVariable(mod)) |variable| {
2544 if (variable.is_const) break :blk self.rodata_section_index.?;
2545 if (variable.init.toValue().isUndefDeep(mod)) {
2546 const mode = self.base.options.optimize_mode;
2547 if (mode == .Debug or mode == .ReleaseSafe) break :blk self.data_section_index.?;
2548 break :blk self.bss_section_index.?;
26302549 }
2631 break :blk self.rodata_section_index.?;
2632 },
2633 }
2550 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
2551 // intrusive check for all zeroes than this?
2552 const is_all_zeroes = for (code) |byte| {
2553 if (byte != 0) break false;
2554 } else true;
2555 if (is_all_zeroes) break :blk self.bss_section_index.?;
2556 break :blk self.data_section_index.?;
2557 }
2558 break :blk self.rodata_section_index.?;
2559 },
26342560 };
26352561 return shdr_index;
26362562}
......@@ -2655,7 +2581,10 @@ fn updateDeclCode(
26552581 const sym = self.symbol(sym_index);
26562582 const esym = &zig_module.local_esyms.items[sym.esym_index];
26572583 const atom_ptr = sym.atom(self).?;
2658 const shdr_index = sym.output_section_index;
2584
2585 const shdr_index = self.getDeclShdrIndex(decl_index, code);
2586 sym.output_section_index = shdr_index;
2587 atom_ptr.output_section_index = shdr_index;
26592588
26602589 sym.name_offset = try self.strtab.insert(gpa, decl_name);
26612590 atom_ptr.alive = true;
......@@ -2908,9 +2837,14 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
29082837 },
29092838 };
29102839
2840 const output_section_index = switch (sym.kind) {
2841 .code => self.text_section_index.?,
2842 .const_data => self.rodata_section_index.?,
2843 };
29112844 const local_sym = self.symbol(symbol_index);
2912 const phdr_index = self.phdr_to_shdr_table.get(local_sym.output_section_index).?;
2845 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
29132846 local_sym.name_offset = name_str_index;
2847 local_sym.output_section_index = output_section_index;
29142848 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
29152849 local_esym.st_name = name_str_index;
29162850 local_esym.st_info |= elf.STT_OBJECT;
......@@ -2920,6 +2854,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
29202854 atom_ptr.name_offset = name_str_index;
29212855 atom_ptr.alignment = required_alignment;
29222856 atom_ptr.size = code.len;
2857 atom_ptr.output_section_index = output_section_index;
29232858
29242859 try atom_ptr.allocate(self);
29252860 errdefer self.freeDeclMetadata(symbol_index);
......@@ -2938,7 +2873,7 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
29382873 try self.got.writeEntry(self, gop.index);
29392874
29402875 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
2941 const file_offset = self.shdrs.items[local_sym.output_section_index].sh_offset + section_offset;
2876 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
29422877 try self.base.file.?.pwriteAll(code, file_offset);
29432878}
29442879
......@@ -2966,7 +2901,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
29662901 const name = self.strtab.get(name_str_index).?;
29672902
29682903 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
2969 const sym_index = try zig_module.addAtom(self.rodata_section_index.?, self);
2904 const sym_index = try zig_module.addAtom(self);
29702905
29712906 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{
29722907 .none = {},
......@@ -2988,6 +2923,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
29882923 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
29892924 const local_sym = self.symbol(sym_index);
29902925 local_sym.name_offset = name_str_index;
2926 local_sym.output_section_index = self.rodata_section_index.?;
29912927 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
29922928 local_esym.st_name = name_str_index;
29932929 local_esym.st_info |= elf.STT_OBJECT;
......@@ -2997,6 +2933,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
29972933 atom_ptr.name_offset = name_str_index;
29982934 atom_ptr.alignment = required_alignment;
29992935 atom_ptr.size = code.len;
2936 atom_ptr.output_section_index = self.rodata_section_index.?;
30002937
30012938 try atom_ptr.allocate(self);
30022939 errdefer self.freeDeclMetadata(sym_index);
......@@ -4014,6 +3951,54 @@ fn reportParseError(
40143951 });
40153952}
40163953
3954fn fmtShdrs(self: *Elf) std.fmt.Formatter(formatShdrs) {
3955 return .{ .data = self };
3956}
3957
3958fn formatShdrs(
3959 self: *Elf,
3960 comptime unused_fmt_string: []const u8,
3961 options: std.fmt.FormatOptions,
3962 writer: anytype,
3963) !void {
3964 _ = options;
3965 _ = unused_fmt_string;
3966 for (self.shdrs.items, 0..) |shdr, i| {
3967 try writer.print("shdr({d}) : phdr({?d}) : {s} : @{x} ({x}) : align({x}) : size({x})\n", .{
3968 i, self.phdr_to_shdr_table.get(@intCast(i)),
3969 self.shstrtab.getAssumeExists(shdr.sh_name), shdr.sh_offset,
3970 shdr.sh_addr, shdr.sh_addralign,
3971 shdr.sh_size,
3972 });
3973 }
3974}
3975
3976fn fmtPhdrs(self: *Elf) std.fmt.Formatter(formatPhdrs) {
3977 return .{ .data = self };
3978}
3979
3980fn formatPhdrs(
3981 self: *Elf,
3982 comptime unused_fmt_string: []const u8,
3983 options: std.fmt.FormatOptions,
3984 writer: anytype,
3985) !void {
3986 _ = options;
3987 _ = unused_fmt_string;
3988 for (self.phdrs.items, 0..) |phdr, i| {
3989 const write = phdr.p_flags & elf.PF_W != 0;
3990 const read = phdr.p_flags & elf.PF_R != 0;
3991 const exec = phdr.p_flags & elf.PF_X != 0;
3992 var flags: [3]u8 = [_]u8{'_'} ** 3;
3993 if (exec) flags[0] = 'X';
3994 if (write) flags[1] = 'W';
3995 if (read) flags[2] = 'R';
3996 try writer.print("phdr({d}) : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})\n", .{
3997 i, flags, phdr.p_offset, phdr.p_vaddr, phdr.p_align, phdr.p_filesz, phdr.p_memsz,
3998 });
3999 }
4000}
4001
40174002fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {
40184003 return .{ .data = self };
40194004}
......@@ -4053,6 +4038,10 @@ fn fmtDumpState(
40534038 try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
40544039 }
40554040 try writer.print("{}\n", .{self.got.fmt(self)});
4041 try writer.writeAll("Output shdrs\n");
4042 try writer.print("{}\n", .{self.fmtShdrs()});
4043 try writer.writeAll("Output phdrs\n");
4044 try writer.print("{}\n", .{self.fmtPhdrs()});
40564045}
40574046
40584047/// Binary search
src/link/Elf/Atom.zig+10-5
......@@ -17,7 +17,7 @@ alignment: Alignment = .@"1",
1717input_section_index: Index = 0,
1818
1919/// Index of the output section.
20output_section_index: Index = 0,
20output_section_index: u16 = 0,
2121
2222/// Index of the input section containing this atom's relocs.
2323relocs_section_index: Index = 0,
......@@ -53,6 +53,11 @@ pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {
5353 return object.shdrs.items[self.input_section_index];
5454}
5555
56pub fn outputShndx(self: Atom) ?u16 {
57 if (self.output_section_index == 0) return null;
58 return self.output_section_index;
59}
60
5661pub fn codeInObject(self: Atom, elf_file: *Elf) error{Overflow}![]const u8 {
5762 const object = elf_file.file(self.file_index).?.object;
5863 return object.shdrContents(self.input_section_index);
......@@ -109,8 +114,8 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
109114}
110115
111116pub fn allocate(self: *Atom, elf_file: *Elf) !void {
112 const shdr = &elf_file.shdrs.items[self.output_section_index];
113 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.output_section_index).?;
117 const shdr = &elf_file.shdrs.items[self.outputShndx().?];
118 const meta = elf_file.last_atom_and_free_list_table.getPtr(self.outputShndx().?).?;
114119 const free_list = &meta.free_list;
115120 const last_atom_index = &meta.last_atom_index;
116121 const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
......@@ -179,7 +184,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
179184 true;
180185 if (expand_section) {
181186 const needed_size = (self.value + self.size) - shdr.sh_addr;
182 try elf_file.growAllocSection(self.output_section_index, needed_size);
187 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
183188 last_atom_index.* = self.atom_index;
184189
185190 if (elf_file.dwarf) |_| {
......@@ -234,7 +239,7 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
234239
235240 const gpa = elf_file.base.allocator;
236241 const zig_module = elf_file.file(self.file_index).?.zig_module;
237 const shndx = self.output_section_index;
242 const shndx = self.outputShndx().?;
238243 const meta = elf_file.last_atom_and_free_list_table.getPtr(shndx).?;
239244 const free_list = &meta.free_list;
240245 const last_atom_index = &meta.last_atom_index;
src/link/Elf/Object.zig+4-4
......@@ -272,9 +272,9 @@ fn initSymtab(self: *Object, elf_file: *Elf) !void {
272272 sym_ptr.atom_index = if (sym.st_shndx == elf.SHN_ABS) 0 else self.atoms.items[sym.st_shndx];
273273 sym_ptr.file_index = self.index;
274274 sym_ptr.output_section_index = if (sym_ptr.atom(elf_file)) |atom_ptr|
275 atom_ptr.output_section_index
275 atom_ptr.outputShndx().?
276276 else
277 0;
277 elf.SHN_UNDEF;
278278 }
279279
280280 for (self.symtab[first_global..]) |sym| {
......@@ -440,9 +440,9 @@ pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
440440 else => self.atoms.items[esym.st_shndx],
441441 };
442442 const output_section_index = if (elf_file.atom(atom_index)) |atom|
443 atom.output_section_index
443 atom.outputShndx().?
444444 else
445 0;
445 elf.SHN_UNDEF;
446446 global.value = esym.st_value;
447447 global.atom_index = atom_index;
448448 global.esym_index = esym_index;
src/link/Elf/Symbol.zig+9-4
......@@ -33,10 +33,15 @@ extra_index: u32 = 0,
3333pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
3434 const file_ptr = symbol.file(elf_file).?;
3535 // if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
36 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and
36 return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.outputShndx() == null and
3737 file_ptr != .linker_defined;
3838}
3939
40pub fn outputShndx(symbol: Symbol) ?u16 {
41 if (symbol.output_section_index == 0) return null;
42 return symbol.output_section_index;
43}
44
4045pub fn isLocal(symbol: Symbol) bool {
4146 return !(symbol.flags.import or symbol.flags.@"export");
4247}
......@@ -183,7 +188,7 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
183188 // if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
184189 if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
185190 break :blk elf.SHN_ABS;
186 break :blk symbol.output_section_index;
191 break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
187192 };
188193 const st_value = blk: {
189194 // if (symbol.flags.copy_rel) break :blk symbol.address(.{}, elf_file);
......@@ -276,8 +281,8 @@ fn format2(
276281 } else {
277282 try writer.writeAll(" : absolute");
278283 }
279 } else if (symbol.output_section_index != 0) {
280 try writer.print(" : sect({d})", .{symbol.output_section_index});
284 } else if (symbol.outputShndx()) |shndx| {
285 try writer.print(" : sect({d})", .{shndx});
281286 }
282287 if (symbol.atom(ctx.elf_file)) |atom_ptr| {
283288 try writer.print(" : atom({d})", .{atom_ptr.atom_index});
src/link/Elf/ZigModule.zig+19-5
......@@ -49,21 +49,19 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
4949 return index | 0x10000000;
5050}
5151
52pub fn addAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {
52pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
5353 const gpa = elf_file.base.allocator;
5454
5555 const atom_index = try elf_file.addAtom();
5656 try self.atoms.putNoClobber(gpa, atom_index, {});
5757 const atom_ptr = elf_file.atom(atom_index).?;
5858 atom_ptr.file_index = self.index;
59 atom_ptr.output_section_index = output_section_index;
6059
6160 const symbol_index = try elf_file.addSymbol();
6261 try self.local_symbols.append(gpa, symbol_index);
6362 const symbol_ptr = elf_file.symbol(symbol_index);
6463 symbol_ptr.file_index = self.index;
6564 symbol_ptr.atom_index = atom_index;
66 symbol_ptr.output_section_index = output_section_index;
6765
6866 const esym_index = try self.addLocalEsym(gpa);
6967 const esym = &self.local_esyms.items[esym_index];
......@@ -98,9 +96,9 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
9896 else => esym.st_shndx,
9997 };
10098 const output_section_index = if (elf_file.atom(atom_index)) |atom|
101 atom.output_section_index
99 atom.outputShndx().?
102100 else
103 0;
101 elf.SHN_UNDEF;
104102 global.value = esym.st_value;
105103 global.atom_index = atom_index;
106104 global.esym_index = esym_index;
......@@ -157,6 +155,22 @@ pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {
157155 }
158156}
159157
158pub fn markLive(self: *ZigModule, elf_file: *Elf) void {
159 for (self.globals(), 0..) |index, i| {
160 const esym = self.global_esyms.items[i];
161 if (esym.st_bind() == elf.STB_WEAK) continue;
162
163 const global = elf_file.symbol(index);
164 const file = global.file(elf_file) orelse continue;
165 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
166 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
167 if (should_keep and !file.isAlive()) {
168 file.setAlive();
169 file.markLive(elf_file);
170 }
171 }
172}
173
160174pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
161175 for (self.locals()) |local_index| {
162176 const local = elf_file.symbol(local_index);
src/link/Elf/file.zig+1-1
......@@ -84,7 +84,7 @@ pub const File = union(enum) {
8484
8585 pub fn markLive(file: File, elf_file: *Elf) void {
8686 switch (file) {
87 .zig_module, .linker_defined => unreachable,
87 .linker_defined => unreachable,
8888 inline else => |x| x.markLive(elf_file),
8989 }
9090 }