| ... | @@ -43,6 +43,12 @@ phdr_load_ro_index: ?u16 = null, | ... | @@ -43,6 +43,12 @@ phdr_load_ro_index: ?u16 = null, |
| 43 | phdr_load_rw_index: ?u16 = null, | 43 | phdr_load_rw_index: ?u16 = null, |
| 44 | /// The index into the program headers of a PT_LOAD program header with zerofill data. | 44 | /// The index into the program headers of a PT_LOAD program header with zerofill data. |
| 45 | phdr_load_zerofill_index: ?u16 = null, | 45 | phdr_load_zerofill_index: ?u16 = null, |
| | 46 | /// The index into the program headers of the PT_TLS program header. |
| | 47 | phdr_tls_index: ?u16 = null, |
| | 48 | /// The index into the program headers of a PT_LOAD program header with TLS data. |
| | 49 | phdr_load_tls_data_index: ?u16 = null, |
| | 50 | /// The index into the program headers of a PT_LOAD program header with TLS zerofill data. |
| | 51 | phdr_load_tls_zerofill_index: ?u16 = null, |
| 46 | | 52 | |
| 47 | entry_addr: ?u64 = null, | 53 | entry_addr: ?u64 = null, |
| 48 | page_size: u32, | 54 | page_size: u32, |
| ... | @@ -56,10 +62,13 @@ strtab: StringTable(.strtab) = .{}, | ... | @@ -56,10 +62,13 @@ strtab: StringTable(.strtab) = .{}, |
| 56 | /// Representation of the GOT table as committed to the file. | 62 | /// Representation of the GOT table as committed to the file. |
| 57 | got: GotSection = .{}, | 63 | got: GotSection = .{}, |
| 58 | | 64 | |
| | 65 | /// Tracked section headers |
| 59 | text_section_index: ?u16 = null, | 66 | text_section_index: ?u16 = null, |
| 60 | rodata_section_index: ?u16 = null, | 67 | rodata_section_index: ?u16 = null, |
| 61 | data_section_index: ?u16 = null, | 68 | data_section_index: ?u16 = null, |
| 62 | bss_section_index: ?u16 = null, | 69 | bss_section_index: ?u16 = null, |
| | 70 | tdata_section_index: ?u16 = null, |
| | 71 | tbss_section_index: ?u16 = null, |
| 63 | eh_frame_section_index: ?u16 = null, | 72 | eh_frame_section_index: ?u16 = null, |
| 64 | eh_frame_hdr_section_index: ?u16 = null, | 73 | eh_frame_hdr_section_index: ?u16 = null, |
| 65 | dynamic_section_index: ?u16 = null, | 74 | dynamic_section_index: ?u16 = null, |
| ... | @@ -238,7 +247,8 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { | ... | @@ -238,7 +247,8 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { |
| 238 | else | 247 | else |
| 239 | elf.VER_NDX_LOCAL; | 248 | elf.VER_NDX_LOCAL; |
| 240 | | 249 | |
| 241 | var dwarf: ?Dwarf = if (!options.strip and options.module != null) | 250 | const use_llvm = options.use_llvm; |
| | 251 | var dwarf: ?Dwarf = if (!options.strip and options.module != null and !use_llvm) |
| 242 | Dwarf.init(gpa, &self.base, options.target) | 252 | Dwarf.init(gpa, &self.base, options.target) |
| 243 | else | 253 | else |
| 244 | null; | 254 | null; |
| ... | @@ -255,7 +265,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { | ... | @@ -255,7 +265,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf { |
| 255 | .page_size = page_size, | 265 | .page_size = page_size, |
| 256 | .default_sym_version = default_sym_version, | 266 | .default_sym_version = default_sym_version, |
| 257 | }; | 267 | }; |
| 258 | const use_llvm = options.use_llvm; | | |
| 259 | if (use_llvm and options.module != null) { | 268 | if (use_llvm and options.module != null) { |
| 260 | self.llvm_object = try LlvmObject.create(gpa, options); | 269 | self.llvm_object = try LlvmObject.create(gpa, options); |
| 261 | } | 270 | } |
| ... | @@ -358,10 +367,12 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { | ... | @@ -358,10 +367,12 @@ fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 { |
| 358 | } | 367 | } |
| 359 | } | 368 | } |
| 360 | | 369 | |
| 361 | for (self.shdrs.items) |section| { | 370 | for (self.shdrs.items) |shdr| { |
| 362 | const increased_size = padToIdeal(section.sh_size); | 371 | // SHT_NOBITS takes no physical space in the output file so set its size to 0. |
| 363 | const test_end = section.sh_offset + increased_size; | 372 | const sh_size = if (shdr.sh_type == elf.SHT_NOBITS) 0 else shdr.sh_size; |
| 364 | if (end > section.sh_offset and start < test_end) { | 373 | const increased_size = padToIdeal(sh_size); |
| | 374 | const test_end = shdr.sh_offset + increased_size; |
| | 375 | if (end > shdr.sh_offset and start < test_end) { |
| 365 | return test_end; | 376 | return test_end; |
| 366 | } | 377 | } |
| 367 | } | 378 | } |
| ... | @@ -429,15 +440,15 @@ pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory} | ... | @@ -429,15 +440,15 @@ pub fn allocateSegment(self: *Elf, opts: AllocateSegmentOpts) error{OutOfMemory} |
| 429 | const addr = opts.addr orelse blk: { | 440 | const addr = opts.addr orelse blk: { |
| 430 | const reserved_capacity = self.calcImageBase() * 4; | 441 | const reserved_capacity = self.calcImageBase() * 4; |
| 431 | // Calculate largest VM address | 442 | // Calculate largest VM address |
| 432 | const count = self.phdrs.items.len; | | |
| 433 | var addresses = std.ArrayList(u64).init(gpa); | 443 | var addresses = std.ArrayList(u64).init(gpa); |
| 434 | defer addresses.deinit(); | 444 | defer addresses.deinit(); |
| 435 | try addresses.ensureTotalCapacityPrecise(count); | 445 | try addresses.ensureTotalCapacityPrecise(self.phdrs.items.len); |
| 436 | for (self.phdrs.items) |phdr| { | 446 | for (self.phdrs.items) |phdr| { |
| | 447 | if (phdr.p_type != elf.PT_LOAD) continue; |
| 437 | addresses.appendAssumeCapacity(phdr.p_vaddr + reserved_capacity); | 448 | addresses.appendAssumeCapacity(phdr.p_vaddr + reserved_capacity); |
| 438 | } | 449 | } |
| 439 | mem.sort(u64, addresses.items, {}, std.sort.asc(u64)); | 450 | mem.sort(u64, addresses.items, {}, std.sort.asc(u64)); |
| 440 | break :blk mem.alignForward(u64, addresses.items[count - 1], opts.alignment); | 451 | break :blk mem.alignForward(u64, addresses.pop(), opts.alignment); |
| 441 | }; | 452 | }; |
| 442 | log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ | 453 | log.debug("allocating phdr({d})({c}{c}{c}) from 0x{x} to 0x{x} (0x{x} - 0x{x})", .{ |
| 443 | index, | 454 | index, |
| ... | @@ -492,7 +503,7 @@ pub fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{Ou | ... | @@ -492,7 +503,7 @@ pub fn allocateAllocSection(self: *Elf, opts: AllocateAllocSectionOpts) error{Ou |
| 492 | .sh_flags = opts.flags, | 503 | .sh_flags = opts.flags, |
| 493 | .sh_addr = phdr.p_vaddr, | 504 | .sh_addr = phdr.p_vaddr, |
| 494 | .sh_offset = phdr.p_offset, | 505 | .sh_offset = phdr.p_offset, |
| 495 | .sh_size = phdr.p_filesz, | 506 | .sh_size = phdr.p_memsz, |
| 496 | .sh_link = 0, | 507 | .sh_link = 0, |
| 497 | .sh_info = 0, | 508 | .sh_info = 0, |
| 498 | .sh_addralign = opts.alignment, | 509 | .sh_addralign = opts.alignment, |
| ... | @@ -543,7 +554,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -543,7 +554,6 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 543 | }; | 554 | }; |
| 544 | const ptr_size: u8 = self.ptrWidthBytes(); | 555 | const ptr_size: u8 = self.ptrWidthBytes(); |
| 545 | const is_linux = self.base.options.target.os.tag == .linux; | 556 | const is_linux = self.base.options.target.os.tag == .linux; |
| 546 | const large_addrspace = self.base.options.target.ptrBitWidth() >= 32; | | |
| 547 | const image_base = self.calcImageBase(); | 557 | const image_base = self.calcImageBase(); |
| 548 | | 558 | |
| 549 | if (self.phdr_table_index == null) { | 559 | if (self.phdr_table_index == null) { |
| ... | @@ -566,23 +576,16 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -566,23 +576,16 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 566 | } | 576 | } |
| 567 | | 577 | |
| 568 | if (self.phdr_table_load_index == null) { | 578 | if (self.phdr_table_load_index == null) { |
| 569 | self.phdr_table_load_index = @intCast(self.phdrs.items.len); | 579 | self.phdr_table_load_index = try self.allocateSegment(.{ |
| 570 | try self.phdrs.append(gpa, .{ | 580 | .addr = image_base, |
| 571 | .p_type = elf.PT_LOAD, | 581 | .size = 0, |
| 572 | .p_offset = 0, | 582 | .alignment = self.page_size, |
| 573 | .p_filesz = 0, | | |
| 574 | .p_vaddr = image_base, | | |
| 575 | .p_paddr = image_base, | | |
| 576 | .p_memsz = 0, | | |
| 577 | .p_align = self.page_size, | | |
| 578 | .p_flags = elf.PF_R, | | |
| 579 | }); | 583 | }); |
| 580 | self.phdr_table_dirty = true; | 584 | self.phdr_table_dirty = true; |
| 581 | } | 585 | } |
| 582 | | 586 | |
| 583 | if (self.phdr_load_re_index == null) { | 587 | if (self.phdr_load_re_index == null) { |
| 584 | self.phdr_load_re_index = try self.allocateSegment(.{ | 588 | self.phdr_load_re_index = try self.allocateSegment(.{ |
| 585 | .addr = self.defaultEntryAddress(), | | |
| 586 | .size = self.base.options.program_code_size_hint, | 589 | .size = self.base.options.program_code_size_hint, |
| 587 | .alignment = self.page_size, | 590 | .alignment = self.page_size, |
| 588 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, | 591 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, |
| ... | @@ -591,12 +594,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -591,12 +594,10 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 591 | } | 594 | } |
| 592 | | 595 | |
| 593 | if (self.phdr_got_index == null) { | 596 | if (self.phdr_got_index == null) { |
| 594 | const addr: u64 = if (large_addrspace) 0x4000000 else 0x8000; | | |
| 595 | // We really only need ptr alignment but since we are using PROGBITS, linux requires | 597 | // We really only need ptr alignment but since we are using PROGBITS, linux requires |
| 596 | // page align. | 598 | // page align. |
| 597 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); | 599 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 598 | self.phdr_got_index = try self.allocateSegment(.{ | 600 | self.phdr_got_index = try self.allocateSegment(.{ |
| 599 | .addr = addr, | | |
| 600 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, | 601 | .size = @as(u64, ptr_size) * self.base.options.symbol_count_hint, |
| 601 | .alignment = alignment, | 602 | .alignment = alignment, |
| 602 | .flags = elf.PF_R | elf.PF_W, | 603 | .flags = elf.PF_R | elf.PF_W, |
| ... | @@ -604,10 +605,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -604,10 +605,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 604 | } | 605 | } |
| 605 | | 606 | |
| 606 | if (self.phdr_load_ro_index == null) { | 607 | if (self.phdr_load_ro_index == null) { |
| 607 | const addr: u64 = if (large_addrspace) 0xc000000 else 0xa000; | | |
| 608 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); | 608 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 609 | self.phdr_load_ro_index = try self.allocateSegment(.{ | 609 | self.phdr_load_ro_index = try self.allocateSegment(.{ |
| 610 | .addr = addr, | | |
| 611 | .size = 1024, | 610 | .size = 1024, |
| 612 | .alignment = alignment, | 611 | .alignment = alignment, |
| 613 | .flags = elf.PF_R | elf.PF_W, | 612 | .flags = elf.PF_R | elf.PF_W, |
| ... | @@ -615,10 +614,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -615,10 +614,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 615 | } | 614 | } |
| 616 | | 615 | |
| 617 | if (self.phdr_load_rw_index == null) { | 616 | if (self.phdr_load_rw_index == null) { |
| 618 | const addr: u64 = if (large_addrspace) 0x10000000 else 0xc000; | | |
| 619 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); | 617 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 620 | self.phdr_load_rw_index = try self.allocateSegment(.{ | 618 | self.phdr_load_rw_index = try self.allocateSegment(.{ |
| 621 | .addr = addr, | | |
| 622 | .size = 1024, | 619 | .size = 1024, |
| 623 | .alignment = alignment, | 620 | .alignment = alignment, |
| 624 | .flags = elf.PF_R | elf.PF_W, | 621 | .flags = elf.PF_R | elf.PF_W, |
| ... | @@ -626,10 +623,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -626,10 +623,8 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 626 | } | 623 | } |
| 627 | | 624 | |
| 628 | if (self.phdr_load_zerofill_index == null) { | 625 | if (self.phdr_load_zerofill_index == null) { |
| 629 | const addr: u64 = if (large_addrspace) 0x14000000 else 0xf000; | | |
| 630 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); | 626 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| 631 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ | 627 | self.phdr_load_zerofill_index = try self.allocateSegment(.{ |
| 632 | .addr = addr, | | |
| 633 | .size = 0, | 628 | .size = 0, |
| 634 | .alignment = alignment, | 629 | .alignment = alignment, |
| 635 | .flags = elf.PF_R | elf.PF_W, | 630 | .flags = elf.PF_R | elf.PF_W, |
| ... | @@ -639,6 +634,53 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -639,6 +634,53 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 639 | phdr.p_memsz = 1024; | 634 | phdr.p_memsz = 1024; |
| 640 | } | 635 | } |
| 641 | | 636 | |
| | 637 | if (!self.base.options.single_threaded) { |
| | 638 | if (self.phdr_load_tls_data_index == null) { |
| | 639 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| | 640 | self.phdr_load_tls_data_index = try self.allocateSegment(.{ |
| | 641 | .size = 1024, |
| | 642 | .alignment = alignment, |
| | 643 | .flags = elf.PF_R | elf.PF_W, |
| | 644 | }); |
| | 645 | } |
| | 646 | |
| | 647 | if (self.phdr_load_tls_zerofill_index == null) { |
| | 648 | // TODO .tbss doesn't need any physical or memory representation (aka a loadable segment) |
| | 649 | // since the loader only cares about the PT_TLS to work out TLS size. However, when |
| | 650 | // relocating we need to have .tdata and .tbss contiguously laid out so that we can |
| | 651 | // work out correct offsets to the start/end of the TLS segment. I am thinking that |
| | 652 | // perhaps it's possible to completely spoof it by having an abstracted mechanism |
| | 653 | // for this that wouldn't require us to explicitly track .tbss. Anyhow, for now, |
| | 654 | // we go the savage route of treating .tbss like .bss. |
| | 655 | const alignment = if (is_linux) self.page_size else @as(u16, ptr_size); |
| | 656 | self.phdr_load_tls_zerofill_index = try self.allocateSegment(.{ |
| | 657 | .size = 0, |
| | 658 | .alignment = alignment, |
| | 659 | .flags = elf.PF_R | elf.PF_W, |
| | 660 | }); |
| | 661 | const phdr = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?]; |
| | 662 | phdr.p_offset = self.phdrs.items[self.phdr_load_tls_data_index.?].p_offset; // .tbss overlaps .tdata |
| | 663 | phdr.p_memsz = 1024; |
| | 664 | } |
| | 665 | |
| | 666 | if (self.phdr_tls_index == null) { |
| | 667 | self.phdr_tls_index = @intCast(self.phdrs.items.len); |
| | 668 | const phdr_tdata = &self.phdrs.items[self.phdr_load_tls_data_index.?]; |
| | 669 | const phdr_tbss = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?]; |
| | 670 | try self.phdrs.append(gpa, .{ |
| | 671 | .p_type = elf.PT_TLS, |
| | 672 | .p_offset = phdr_tdata.p_offset, |
| | 673 | .p_vaddr = phdr_tdata.p_vaddr, |
| | 674 | .p_paddr = phdr_tdata.p_paddr, |
| | 675 | .p_filesz = phdr_tdata.p_filesz, |
| | 676 | .p_memsz = phdr_tbss.p_vaddr + phdr_tbss.p_memsz - phdr_tdata.p_vaddr, |
| | 677 | .p_align = ptr_size, |
| | 678 | .p_flags = elf.PF_R, |
| | 679 | }); |
| | 680 | self.phdr_table_dirty = true; |
| | 681 | } |
| | 682 | } |
| | 683 | |
| 642 | if (self.shstrtab_section_index == null) { | 684 | if (self.shstrtab_section_index == null) { |
| 643 | assert(self.shstrtab.buffer.items.len == 0); | 685 | assert(self.shstrtab.buffer.items.len == 0); |
| 644 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 | 686 | try self.shstrtab.buffer.append(gpa, 0); // need a 0 at position 0 |
| ... | @@ -707,6 +749,31 @@ pub fn populateMissingMetadata(self: *Elf) !void { | ... | @@ -707,6 +749,31 @@ pub fn populateMissingMetadata(self: *Elf) !void { |
| 707 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{}); | 749 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.bss_section_index.?, .{}); |
| 708 | } | 750 | } |
| 709 | | 751 | |
| | 752 | if (self.phdr_load_tls_data_index) |phdr_index| { |
| | 753 | if (self.tdata_section_index == null) { |
| | 754 | self.tdata_section_index = try self.allocateAllocSection(.{ |
| | 755 | .name = ".tdata", |
| | 756 | .phdr_index = phdr_index, |
| | 757 | .alignment = ptr_size, |
| | 758 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, |
| | 759 | }); |
| | 760 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.tdata_section_index.?, .{}); |
| | 761 | } |
| | 762 | } |
| | 763 | |
| | 764 | if (self.phdr_load_tls_zerofill_index) |phdr_index| { |
| | 765 | if (self.tbss_section_index == null) { |
| | 766 | self.tbss_section_index = try self.allocateAllocSection(.{ |
| | 767 | .name = ".tbss", |
| | 768 | .phdr_index = phdr_index, |
| | 769 | .alignment = ptr_size, |
| | 770 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, |
| | 771 | .type = elf.SHT_NOBITS, |
| | 772 | }); |
| | 773 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.tbss_section_index.?, .{}); |
| | 774 | } |
| | 775 | } |
| | 776 | |
| 710 | if (self.symtab_section_index == null) { | 777 | if (self.symtab_section_index == null) { |
| 711 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); | 778 | const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym); |
| 712 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); | 779 | const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym); |
| ... | @@ -844,10 +911,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -844,10 +911,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 844 | if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) { | 911 | if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) { |
| 845 | // Must move the entire section. | 912 | // Must move the entire section. |
| 846 | const new_offset = self.findFreeSpace(needed_size, self.page_size); | 913 | const new_offset = self.findFreeSpace(needed_size, self.page_size); |
| 847 | const existing_size = if (self.last_atom_and_free_list_table.get(shdr_index)) |meta| blk: { | 914 | const existing_size = shdr.sh_size; |
| 848 | const last = self.atom(meta.last_atom_index) orelse break :blk 0; | | |
| 849 | break :blk (last.value + last.size) - phdr.p_vaddr; | | |
| 850 | } else shdr.sh_size; | | |
| 851 | shdr.sh_size = 0; | 915 | shdr.sh_size = 0; |
| 852 | | 916 | |
| 853 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ | 917 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ |
| ... | @@ -857,12 +921,18 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -857,12 +921,18 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 857 | }); | 921 | }); |
| 858 | | 922 | |
| 859 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size); | 923 | const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size); |
| | 924 | // TODO figure out what to about this error condition - how to communicate it up. |
| 860 | if (amt != existing_size) return error.InputOutput; | 925 | if (amt != existing_size) return error.InputOutput; |
| 861 | | 926 | |
| 862 | shdr.sh_offset = new_offset; | 927 | shdr.sh_offset = new_offset; |
| 863 | phdr.p_offset = new_offset; | 928 | phdr.p_offset = new_offset; |
| 864 | } | 929 | } |
| 865 | | 930 | |
| | 931 | shdr.sh_size = needed_size; |
| | 932 | if (!is_zerofill) { |
| | 933 | phdr.p_filesz = needed_size; |
| | 934 | } |
| | 935 | |
| 866 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); | 936 | const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr); |
| 867 | if (needed_size > mem_capacity) { | 937 | if (needed_size > mem_capacity) { |
| 868 | // We are exceeding our allocated VM capacity so we need to shift everything in memory | 938 | // We are exceeding our allocated VM capacity so we need to shift everything in memory |
| ... | @@ -889,13 +959,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { | ... | @@ -889,13 +959,8 @@ pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| 889 | } | 959 | } |
| 890 | } | 960 | } |
| 891 | | 961 | |
| 892 | shdr.sh_size = needed_size; | | |
| 893 | phdr.p_memsz = needed_size; | 962 | phdr.p_memsz = needed_size; |
| 894 | | 963 | |
| 895 | if (!is_zerofill) { | | |
| 896 | phdr.p_filesz = needed_size; | | |
| 897 | } | | |
| 898 | | | |
| 899 | self.markDirty(shdr_index, phdr_index); | 964 | self.markDirty(shdr_index, phdr_index); |
| 900 | } | 965 | } |
| 901 | | 966 | |
| ... | @@ -965,21 +1030,15 @@ pub fn growNonAllocSection( | ... | @@ -965,21 +1030,15 @@ pub fn growNonAllocSection( |
| 965 | const shdr = &self.shdrs.items[shdr_index]; | 1030 | const shdr = &self.shdrs.items[shdr_index]; |
| 966 | | 1031 | |
| 967 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { | 1032 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 968 | const existing_size = if (self.symtab_section_index.? == shdr_index) blk: { | 1033 | const existing_size = shdr.sh_size; |
| 969 | const sym_size: u64 = switch (self.ptr_width) { | | |
| 970 | .p32 => @sizeOf(elf.Elf32_Sym), | | |
| 971 | .p64 => @sizeOf(elf.Elf64_Sym), | | |
| 972 | }; | | |
| 973 | break :blk @as(u64, shdr.sh_info) * sym_size; | | |
| 974 | } else shdr.sh_size; | | |
| 975 | shdr.sh_size = 0; | 1034 | shdr.sh_size = 0; |
| 976 | // Move all the symbols to a new file location. | 1035 | // Move all the symbols to a new file location. |
| 977 | const new_offset = self.findFreeSpace(needed_size, min_alignment); | 1036 | const new_offset = self.findFreeSpace(needed_size, min_alignment); |
| 978 | | 1037 | |
| 979 | log.debug("moving '{?s}' from 0x{x} to 0x{x}", .{ | 1038 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ |
| 980 | self.shstrtab.get(shdr.sh_name), | 1039 | self.shstrtab.getAssumeExists(shdr.sh_name), |
| 981 | shdr.sh_offset, | | |
| 982 | new_offset, | 1040 | new_offset, |
| | 1041 | new_offset + existing_size, |
| 983 | }); | 1042 | }); |
| 984 | | 1043 | |
| 985 | if (requires_file_copy) { | 1044 | if (requires_file_copy) { |
| ... | @@ -1223,19 +1282,48 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1223,19 +1282,48 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1223 | try self.allocateObjects(); | 1282 | try self.allocateObjects(); |
| 1224 | self.allocateLinkerDefinedSymbols(); | 1283 | self.allocateLinkerDefinedSymbols(); |
| 1225 | | 1284 | |
| | 1285 | // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't |
| | 1286 | // get mapped by the loader |
| | 1287 | if (self.data_section_index) |data_shndx| blk: { |
| | 1288 | const bss_shndx = self.bss_section_index orelse break :blk; |
| | 1289 | const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?; |
| | 1290 | const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?; |
| | 1291 | self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset; |
| | 1292 | self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset; |
| | 1293 | } |
| | 1294 | |
| | 1295 | // Same treatment for .tbss section. |
| | 1296 | if (self.tdata_section_index) |tdata_shndx| blk: { |
| | 1297 | const tbss_shndx = self.tbss_section_index orelse break :blk; |
| | 1298 | const tdata_phndx = self.phdr_to_shdr_table.get(tdata_shndx).?; |
| | 1299 | const tbss_phndx = self.phdr_to_shdr_table.get(tbss_shndx).?; |
| | 1300 | self.shdrs.items[tbss_shndx].sh_offset = self.shdrs.items[tdata_shndx].sh_offset; |
| | 1301 | self.phdrs.items[tbss_phndx].p_offset = self.phdrs.items[tdata_phndx].p_offset; |
| | 1302 | } |
| | 1303 | |
| | 1304 | if (self.phdr_tls_index) |tls_index| { |
| | 1305 | const tdata_phdr = &self.phdrs.items[self.phdr_load_tls_data_index.?]; |
| | 1306 | const tbss_phdr = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?]; |
| | 1307 | const phdr = &self.phdrs.items[tls_index]; |
| | 1308 | phdr.p_offset = tdata_phdr.p_offset; |
| | 1309 | phdr.p_filesz = tdata_phdr.p_filesz; |
| | 1310 | phdr.p_vaddr = tdata_phdr.p_vaddr; |
| | 1311 | phdr.p_paddr = tdata_phdr.p_vaddr; |
| | 1312 | phdr.p_memsz = tbss_phdr.p_vaddr + tbss_phdr.p_memsz - tdata_phdr.p_vaddr; |
| | 1313 | } |
| | 1314 | |
| 1226 | // Beyond this point, everything has been allocated a virtual address and we can resolve | 1315 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 1227 | // the relocations, and commit objects to file. | 1316 | // the relocations, and commit objects to file. |
| 1228 | if (self.zig_module_index) |index| { | 1317 | if (self.zig_module_index) |index| { |
| 1229 | for (self.file(index).?.zig_module.atoms.keys()) |atom_index| { | 1318 | const zig_module = self.file(index).?.zig_module; |
| | 1319 | for (zig_module.atoms.keys()) |atom_index| { |
| 1230 | const atom_ptr = self.atom(atom_index).?; | 1320 | const atom_ptr = self.atom(atom_index).?; |
| 1231 | if (!atom_ptr.flags.alive) continue; | 1321 | if (!atom_ptr.flags.alive) continue; |
| 1232 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; | 1322 | const shdr = &self.shdrs.items[atom_ptr.outputShndx().?]; |
| 1233 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; | 1323 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1234 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | 1324 | const code = try zig_module.codeAlloc(self, atom_index); |
| 1235 | const code = try gpa.alloc(u8, size); | | |
| 1236 | defer gpa.free(code); | 1325 | defer gpa.free(code); |
| 1237 | const amt = try self.base.file.?.preadAll(code, file_offset); | 1326 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; |
| 1238 | if (amt != code.len) return error.InputOutput; | | |
| 1239 | try atom_ptr.resolveRelocs(self, code); | 1327 | try atom_ptr.resolveRelocs(self, code); |
| 1240 | try self.base.file.?.pwriteAll(code, file_offset); | 1328 | try self.base.file.?.pwriteAll(code, file_offset); |
| 1241 | } | 1329 | } |
| ... | @@ -1268,22 +1356,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1268,22 +1356,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1268 | try self.updateSymtabSize(); | 1356 | try self.updateSymtabSize(); |
| 1269 | try self.writeSymtab(); | 1357 | try self.writeSymtab(); |
| 1270 | | 1358 | |
| 1271 | // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't | | |
| 1272 | // get mapped by the loader | | |
| 1273 | if (self.data_section_index) |data_shndx| blk: { | | |
| 1274 | const bss_shndx = self.bss_section_index orelse break :blk; | | |
| 1275 | const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?; | | |
| 1276 | const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?; | | |
| 1277 | self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset; | | |
| 1278 | self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset; | | |
| 1279 | } | | |
| 1280 | | | |
| 1281 | // Dump the state for easy debugging. | | |
| 1282 | // State can be dumped via `--debug-log link_state`. | | |
| 1283 | if (build_options.enable_logging) { | | |
| 1284 | state_log.debug("{}", .{self.dumpState()}); | | |
| 1285 | } | | |
| 1286 | | | |
| 1287 | if (self.dwarf) |*dw| { | 1359 | if (self.dwarf) |*dw| { |
| 1288 | if (self.debug_abbrev_section_dirty) { | 1360 | if (self.debug_abbrev_section_dirty) { |
| 1289 | try dw.writeDbgAbbrev(); | 1361 | try dw.writeDbgAbbrev(); |
| ... | @@ -1470,6 +1542,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1470,6 +1542,12 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1470 | try self.writeElfHeader(); | 1542 | try self.writeElfHeader(); |
| 1471 | } | 1543 | } |
| 1472 | | 1544 | |
| | 1545 | // Dump the state for easy debugging. |
| | 1546 | // State can be dumped via `--debug-log link_state`. |
| | 1547 | if (build_options.enable_logging) { |
| | 1548 | state_log.debug("{}", .{self.dumpState()}); |
| | 1549 | } |
| | 1550 | |
| 1473 | // The point of flush() is to commit changes, so in theory, nothing should | 1551 | // The point of flush() is to commit changes, so in theory, nothing should |
| 1474 | // be dirty after this. However, it is possible for some things to remain | 1552 | // be dirty after this. However, it is possible for some things to remain |
| 1475 | // dirty because they fail to be written in the event of compile errors, | 1553 | // dirty because they fail to be written in the event of compile errors, |
| ... | @@ -1779,7 +1857,7 @@ fn writeObjects(self: *Elf) !void { | ... | @@ -1779,7 +1857,7 @@ fn writeObjects(self: *Elf) !void { |
| 1779 | | 1857 | |
| 1780 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; | 1858 | const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr; |
| 1781 | log.debug("writing atom({d}) at 0x{x}", .{ atom_ptr.atom_index, file_offset }); | 1859 | log.debug("writing atom({d}) at 0x{x}", .{ atom_ptr.atom_index, file_offset }); |
| 1782 | const code = try atom_ptr.codeInObjectUncompressAlloc(self); | 1860 | const code = try object.codeDecompressAlloc(self, atom_ptr.atom_index); |
| 1783 | defer gpa.free(code); | 1861 | defer gpa.free(code); |
| 1784 | | 1862 | |
| 1785 | try atom_ptr.resolveRelocs(self, code); | 1863 | try atom_ptr.resolveRelocs(self, code); |
| ... | @@ -2785,10 +2863,6 @@ fn updateDeclCode( | ... | @@ -2785,10 +2863,6 @@ fn updateDeclCode( |
| 2785 | try self.got.writeEntry(self, gop.index); | 2863 | try self.got.writeEntry(self, gop.index); |
| 2786 | } | 2864 | } |
| 2787 | | 2865 | |
| 2788 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; | | |
| 2789 | const section_offset = sym.value - self.phdrs.items[phdr_index].p_vaddr; | | |
| 2790 | const file_offset = self.shdrs.items[shdr_index].sh_offset + section_offset; | | |
| 2791 | | | |
| 2792 | if (self.base.child_pid) |pid| { | 2866 | if (self.base.child_pid) |pid| { |
| 2793 | switch (builtin.os.tag) { | 2867 | switch (builtin.os.tag) { |
| 2794 | .linux => { | 2868 | .linux => { |
| ... | @@ -2810,7 +2884,13 @@ fn updateDeclCode( | ... | @@ -2810,7 +2884,13 @@ fn updateDeclCode( |
| 2810 | } | 2884 | } |
| 2811 | } | 2885 | } |
| 2812 | | 2886 | |
| 2813 | try self.base.file.?.pwriteAll(code, file_offset); | 2887 | const shdr = self.shdrs.items[shdr_index]; |
| | 2888 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| | 2889 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; |
| | 2890 | const section_offset = sym.value - self.phdrs.items[phdr_index].p_vaddr; |
| | 2891 | const file_offset = shdr.sh_offset + section_offset; |
| | 2892 | try self.base.file.?.pwriteAll(code, file_offset); |
| | 2893 | } |
| 2814 | } | 2894 | } |
| 2815 | | 2895 | |
| 2816 | pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { | 2896 | pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { |
| ... | @@ -3358,9 +3438,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { | ... | @@ -3358,9 +3438,14 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3358 | // _end | 3438 | // _end |
| 3359 | { | 3439 | { |
| 3360 | const end_symbol = self.symbol(self.end_index.?); | 3440 | const end_symbol = self.symbol(self.end_index.?); |
| | 3441 | end_symbol.value = 0; |
| 3361 | for (self.shdrs.items, 0..) |*shdr, shndx| { | 3442 | for (self.shdrs.items, 0..) |*shdr, shndx| { |
| 3362 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) { | 3443 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 3363 | end_symbol.value = shdr.sh_addr + shdr.sh_size; | 3444 | const phdr_index = self.phdr_to_shdr_table.get(@intCast(shndx)).?; |
| | 3445 | const phdr = self.phdrs.items[phdr_index]; |
| | 3446 | const value = phdr.p_vaddr + phdr.p_memsz; |
| | 3447 | if (end_symbol.value < value) { |
| | 3448 | end_symbol.value = value; |
| 3364 | end_symbol.output_section_index = @intCast(shndx); | 3449 | end_symbol.output_section_index = @intCast(shndx); |
| 3365 | } | 3450 | } |
| 3366 | } | 3451 | } |
| ... | @@ -3424,6 +3509,7 @@ fn updateSymtabSize(self: *Elf) !void { | ... | @@ -3424,6 +3509,7 @@ fn updateSymtabSize(self: *Elf) !void { |
| 3424 | .p64 => @alignOf(elf.Elf64_Sym), | 3509 | .p64 => @alignOf(elf.Elf64_Sym), |
| 3425 | }; | 3510 | }; |
| 3426 | const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; | 3511 | const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; |
| | 3512 | shdr.sh_size = needed_size; |
| 3427 | try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true); | 3513 | try self.growNonAllocSection(self.symtab_section_index.?, needed_size, sym_align, true); |
| 3428 | } | 3514 | } |
| 3429 | | 3515 | |
| ... | @@ -3820,12 +3906,8 @@ pub fn calcImageBase(self: Elf) u64 { | ... | @@ -3820,12 +3906,8 @@ pub fn calcImageBase(self: Elf) u64 { |
| 3820 | }; | 3906 | }; |
| 3821 | } | 3907 | } |
| 3822 | | 3908 | |
| 3823 | pub fn defaultEntryAddress(self: Elf) u64 { | 3909 | pub fn isStatic(self: Elf) bool { |
| 3824 | if (self.entry_addr) |addr| return addr; | 3910 | return self.base.options.link_mode == .Static; |
| 3825 | return switch (self.base.options.target.cpu.arch) { | | |
| 3826 | .spu_2 => 0, | | |
| 3827 | else => default_entry_addr, | | |
| 3828 | }; | | |
| 3829 | } | 3911 | } |
| 3830 | | 3912 | |
| 3831 | pub fn isDynLib(self: Elf) bool { | 3913 | pub fn isDynLib(self: Elf) bool { |
| ... | @@ -4011,6 +4093,22 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO | ... | @@ -4011,6 +4093,22 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO |
| 4011 | return &self.comdat_groups_owners.items[index]; | 4093 | return &self.comdat_groups_owners.items[index]; |
| 4012 | } | 4094 | } |
| 4013 | | 4095 | |
| | 4096 | pub fn tpAddress(self: *Elf) u64 { |
| | 4097 | const index = self.phdr_tls_index orelse return 0; |
| | 4098 | const phdr = self.phdrs.items[index]; |
| | 4099 | return mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align); |
| | 4100 | } |
| | 4101 | |
| | 4102 | pub fn dtpAddress(self: *Elf) u64 { |
| | 4103 | return self.tlsAddress(); |
| | 4104 | } |
| | 4105 | |
| | 4106 | pub fn tlsAddress(self: *Elf) u64 { |
| | 4107 | const index = self.phdr_tls_index orelse return 0; |
| | 4108 | const phdr = self.phdrs.items[index]; |
| | 4109 | return phdr.p_vaddr; |
| | 4110 | } |
| | 4111 | |
| 4014 | const ErrorWithNotes = struct { | 4112 | const ErrorWithNotes = struct { |
| 4015 | /// Allocated index in misc_errors array. | 4113 | /// Allocated index in misc_errors array. |
| 4016 | index: usize, | 4114 | index: usize, |
| ... | @@ -4043,7 +4141,7 @@ const ErrorWithNotes = struct { | ... | @@ -4043,7 +4141,7 @@ const ErrorWithNotes = struct { |
| 4043 | } | 4141 | } |
| 4044 | }; | 4142 | }; |
| 4045 | | 4143 | |
| 4046 | fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { | 4144 | pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes { |
| 4047 | try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1); | 4145 | try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1); |
| 4048 | return self.addErrorWithNotesAssumeCapacity(note_count); | 4146 | return self.addErrorWithNotesAssumeCapacity(note_count); |
| 4049 | } | 4147 | } |