| author | |
| committer | |
| log | 7e31804870cac14063b2468f544fc77a4cbb616f |
| tree | 87e84657c242c95177218185fe34bb5c6f69f035 |
| parent | f87dd43c1285d38d7a0f3092f6487bf1e1f4faa6 |
| parent | e1d5bb365b3b8d645fbdfc4ffb6a14ef3bb0e766 |
| signature |
elf: redo how we allocate atoms extracted from input relocatable object files10 files changed, 1145 insertions(+), 988 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -600,6 +600,7 @@ set(ZIG_STAGE2_SOURCES |
| 600 | 600 | src/link/Elf.zig |
| 601 | 601 | src/link/Elf/Archive.zig |
| 602 | 602 | src/link/Elf/Atom.zig |
| 603 | src/link/Elf/AtomList.zig | |
| 603 | 604 | src/link/Elf/LdScript.zig |
| 604 | 605 | src/link/Elf/LinkerDefined.zig |
| 605 | 606 | src/link/Elf/Object.zig |
src/link/Dwarf.zig+81-63| ... | ... | @@ -261,7 +261,6 @@ pub const Section = struct { |
| 261 | 261 | index: u32, |
| 262 | 262 | first: Unit.Index.Optional, |
| 263 | 263 | last: Unit.Index.Optional, |
| 264 | off: u64, | |
| 265 | 264 | len: u64, |
| 266 | 265 | units: std.ArrayListUnmanaged(Unit), |
| 267 | 266 | |
| ... | ... | @@ -284,9 +283,8 @@ pub const Section = struct { |
| 284 | 283 | .index = std.math.maxInt(u32), |
| 285 | 284 | .first = .none, |
| 286 | 285 | .last = .none, |
| 287 | .off = 0, | |
| 288 | .len = 0, | |
| 289 | 286 | .units = .{}, |
| 287 | .len = 0, | |
| 290 | 288 | }; |
| 291 | 289 | |
| 292 | 290 | fn deinit(sec: *Section, gpa: std.mem.Allocator) void { |
| ... | ... | @@ -295,6 +293,20 @@ pub const Section = struct { |
| 295 | 293 | sec.* = undefined; |
| 296 | 294 | } |
| 297 | 295 | |
| 296 | fn off(sec: Section, dwarf: *Dwarf) u64 { | |
| 297 | if (dwarf.bin_file.cast(.elf)) |elf_file| { | |
| 298 | const zo = elf_file.zigObjectPtr().?; | |
| 299 | const atom = zo.symbol(sec.index).atom(elf_file).?; | |
| 300 | return atom.offset(elf_file); | |
| 301 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { | |
| 302 | const header = if (macho_file.d_sym) |d_sym| | |
| 303 | d_sym.sections.items[sec.index] | |
| 304 | else | |
| 305 | macho_file.sections.items(.header)[sec.index]; | |
| 306 | return header.offset; | |
| 307 | } else unreachable; | |
| 308 | } | |
| 309 | ||
| 298 | 310 | fn addUnit(sec: *Section, header_len: u32, trailer_len: u32, dwarf: *Dwarf) UpdateError!Unit.Index { |
| 299 | 311 | const unit: Unit.Index = @enumFromInt(sec.units.items.len); |
| 300 | 312 | const unit_ptr = try sec.units.addOne(dwarf.gpa); |
| ... | ... | @@ -306,9 +318,9 @@ pub const Section = struct { |
| 306 | 318 | .next = .none, |
| 307 | 319 | .first = .none, |
| 308 | 320 | .last = .none, |
| 309 | .off = 0, | |
| 310 | 321 | .header_len = aligned_header_len, |
| 311 | 322 | .trailer_len = aligned_trailer_len, |
| 323 | .off = 0, | |
| 312 | 324 | .len = aligned_header_len + aligned_trailer_len, |
| 313 | 325 | .entries = .{}, |
| 314 | 326 | .cross_unit_relocs = .{}, |
| ... | ... | @@ -375,12 +387,16 @@ pub const Section = struct { |
| 375 | 387 | fn resize(sec: *Section, dwarf: *Dwarf, len: u64) UpdateError!void { |
| 376 | 388 | if (len <= sec.len) return; |
| 377 | 389 | if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 390 | const zo = elf_file.zigObjectPtr().?; | |
| 391 | const atom = zo.symbol(sec.index).atom(elf_file).?; | |
| 392 | const shndx = atom.output_section_index; | |
| 378 | 393 | if (sec == &dwarf.debug_frame.section) |
| 379 | try elf_file.growAllocSection(sec.index, len) | |
| 394 | try elf_file.growAllocSection(shndx, len, sec.alignment.toByteUnits().?) | |
| 380 | 395 | else |
| 381 | try elf_file.growNonAllocSection(sec.index, len, @intCast(sec.alignment.toByteUnits().?), true); | |
| 382 | const shdr = &elf_file.sections.items(.shdr)[sec.index]; | |
| 383 | sec.off = shdr.sh_offset; | |
| 396 | try elf_file.growNonAllocSection(shndx, len, sec.alignment.toByteUnits().?, true); | |
| 397 | const shdr = elf_file.sections.items(.shdr)[shndx]; | |
| 398 | atom.size = shdr.sh_size; | |
| 399 | atom.alignment = InternPool.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); | |
| 384 | 400 | sec.len = shdr.sh_size; |
| 385 | 401 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { |
| 386 | 402 | const header = if (macho_file.d_sym) |*d_sym| header: { |
| ... | ... | @@ -390,7 +406,6 @@ pub const Section = struct { |
| 390 | 406 | try macho_file.growSection(@intCast(sec.index), len); |
| 391 | 407 | break :header &macho_file.sections.items(.header)[sec.index]; |
| 392 | 408 | }; |
| 393 | sec.off = header.offset; | |
| 394 | 409 | sec.len = header.size; |
| 395 | 410 | } |
| 396 | 411 | } |
| ... | ... | @@ -399,18 +414,21 @@ pub const Section = struct { |
| 399 | 414 | const len = sec.getUnit(sec.first.unwrap() orelse return).off; |
| 400 | 415 | if (len == 0) return; |
| 401 | 416 | for (sec.units.items) |*unit| unit.off -= len; |
| 402 | sec.off += len; | |
| 403 | 417 | sec.len -= len; |
| 404 | 418 | if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 405 | const shdr = &elf_file.sections.items(.shdr)[sec.index]; | |
| 406 | shdr.sh_offset = sec.off; | |
| 419 | const zo = elf_file.zigObjectPtr().?; | |
| 420 | const atom = zo.symbol(sec.index).atom(elf_file).?; | |
| 421 | const shndx = atom.output_section_index; | |
| 422 | const shdr = &elf_file.sections.items(.shdr)[shndx]; | |
| 423 | atom.size = sec.len; | |
| 424 | shdr.sh_offset += len; | |
| 407 | 425 | shdr.sh_size = sec.len; |
| 408 | 426 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { |
| 409 | 427 | const header = if (macho_file.d_sym) |*d_sym| |
| 410 | 428 | &d_sym.sections.items[sec.index] |
| 411 | 429 | else |
| 412 | 430 | &macho_file.sections.items(.header)[sec.index]; |
| 413 | header.offset = @intCast(sec.off); | |
| 431 | header.offset += @intCast(len); | |
| 414 | 432 | header.size = sec.len; |
| 415 | 433 | } |
| 416 | 434 | } |
| ... | ... | @@ -539,9 +557,9 @@ const Unit = struct { |
| 539 | 557 | fn move(unit: *Unit, sec: *Section, dwarf: *Dwarf, new_off: u32) UpdateError!void { |
| 540 | 558 | if (unit.off == new_off) return; |
| 541 | 559 | if (try dwarf.getFile().?.copyRangeAll( |
| 542 | sec.off + unit.off, | |
| 560 | sec.off(dwarf) + unit.off, | |
| 543 | 561 | dwarf.getFile().?, |
| 544 | sec.off + new_off, | |
| 562 | sec.off(dwarf) + new_off, | |
| 545 | 563 | unit.len, |
| 546 | 564 | ) != unit.len) return error.InputOutput; |
| 547 | 565 | unit.off = new_off; |
| ... | ... | @@ -573,7 +591,7 @@ const Unit = struct { |
| 573 | 591 | |
| 574 | 592 | fn replaceHeader(unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 575 | 593 | assert(contents.len == unit.header_len); |
| 576 | try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off); | |
| 594 | try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off); | |
| 577 | 595 | } |
| 578 | 596 | |
| 579 | 597 | fn writeTrailer(unit: *Unit, sec: *Section, dwarf: *Dwarf) UpdateError!void { |
| ... | ... | @@ -605,7 +623,7 @@ const Unit = struct { |
| 605 | 623 | assert(fbs.pos == extended_op_bytes + op_len_bytes); |
| 606 | 624 | writer.writeByte(DW.LNE.padding) catch unreachable; |
| 607 | 625 | assert(fbs.pos >= unit.trailer_len and fbs.pos <= len); |
| 608 | return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + start); | |
| 626 | return dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + start); | |
| 609 | 627 | } |
| 610 | 628 | var trailer = try std.ArrayList(u8).initCapacity(dwarf.gpa, len); |
| 611 | 629 | defer trailer.deinit(); |
| ... | ... | @@ -664,11 +682,11 @@ const Unit = struct { |
| 664 | 682 | assert(trailer.items.len == unit.trailer_len); |
| 665 | 683 | trailer.appendNTimesAssumeCapacity(fill_byte, len - unit.trailer_len); |
| 666 | 684 | assert(trailer.items.len == len); |
| 667 | try dwarf.getFile().?.pwriteAll(trailer.items, sec.off + start); | |
| 685 | try dwarf.getFile().?.pwriteAll(trailer.items, sec.off(dwarf) + start); | |
| 668 | 686 | } |
| 669 | 687 | |
| 670 | 688 | fn resolveRelocs(unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { |
| 671 | const unit_off = sec.off + unit.off; | |
| 689 | const unit_off = sec.off(dwarf) + unit.off; | |
| 672 | 690 | for (unit.cross_unit_relocs.items) |reloc| { |
| 673 | 691 | const target_unit = sec.getUnit(reloc.target_unit); |
| 674 | 692 | try dwarf.resolveReloc( |
| ... | ... | @@ -755,12 +773,12 @@ const Entry = struct { |
| 755 | 773 | dwarf.writeInt(unit_len[0..dwarf.sectionOffsetBytes()], len - dwarf.unitLengthBytes()); |
| 756 | 774 | try dwarf.getFile().?.pwriteAll( |
| 757 | 775 | unit_len[0..dwarf.sectionOffsetBytes()], |
| 758 | sec.off + unit.off + unit.header_len + entry.off, | |
| 776 | sec.off(dwarf) + unit.off + unit.header_len + entry.off, | |
| 759 | 777 | ); |
| 760 | 778 | const buf = try dwarf.gpa.alloc(u8, len - entry.len); |
| 761 | 779 | defer dwarf.gpa.free(buf); |
| 762 | 780 | @memset(buf, DW.CFA.nop); |
| 763 | try dwarf.getFile().?.pwriteAll(buf, sec.off + unit.off + unit.header_len + start); | |
| 781 | try dwarf.getFile().?.pwriteAll(buf, sec.off(dwarf) + unit.off + unit.header_len + start); | |
| 764 | 782 | return; |
| 765 | 783 | } |
| 766 | 784 | const len = unit.getEntry(entry.next.unwrap() orelse return).off - start; |
| ... | ... | @@ -816,7 +834,7 @@ const Entry = struct { |
| 816 | 834 | }, |
| 817 | 835 | } else assert(!sec.pad_to_ideal and len == 0); |
| 818 | 836 | assert(fbs.pos <= len); |
| 819 | try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off + unit.off + unit.header_len + start); | |
| 837 | try dwarf.getFile().?.pwriteAll(fbs.getWritten(), sec.off(dwarf) + unit.off + unit.header_len + start); | |
| 820 | 838 | } |
| 821 | 839 | |
| 822 | 840 | fn resize(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, len: u32) UpdateError!void { |
| ... | ... | @@ -851,15 +869,15 @@ const Entry = struct { |
| 851 | 869 | |
| 852 | 870 | fn replace(entry_ptr: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf, contents: []const u8) UpdateError!void { |
| 853 | 871 | assert(contents.len == entry_ptr.len); |
| 854 | try dwarf.getFile().?.pwriteAll(contents, sec.off + unit.off + unit.header_len + entry_ptr.off); | |
| 872 | try dwarf.getFile().?.pwriteAll(contents, sec.off(dwarf) + unit.off + unit.header_len + entry_ptr.off); | |
| 855 | 873 | if (false) { |
| 856 | 874 | const buf = try dwarf.gpa.alloc(u8, sec.len); |
| 857 | 875 | defer dwarf.gpa.free(buf); |
| 858 | _ = try dwarf.getFile().?.preadAll(buf, sec.off); | |
| 876 | _ = try dwarf.getFile().?.preadAll(buf, sec.off(dwarf)); | |
| 859 | 877 | log.info("Section{{ .first = {}, .last = {}, .off = 0x{x}, .len = 0x{x} }}", .{ |
| 860 | 878 | @intFromEnum(sec.first), |
| 861 | 879 | @intFromEnum(sec.last), |
| 862 | sec.off, | |
| 880 | sec.off(dwarf), | |
| 863 | 881 | sec.len, |
| 864 | 882 | }); |
| 865 | 883 | for (sec.units.items) |*unit_ptr| { |
| ... | ... | @@ -891,9 +909,11 @@ const Entry = struct { |
| 891 | 909 | if (std.debug.runtime_safety) { |
| 892 | 910 | log.err("missing {} from {s}", .{ |
| 893 | 911 | @as(Entry.Index, @enumFromInt(entry - unit.entries.items.ptr)), |
| 894 | std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| | |
| 895 | elf_file.shstrtab.items[elf_file.sections.items(.shdr)[sec.index].sh_name..] | |
| 896 | else if (dwarf.bin_file.cast(.macho)) |macho_file| | |
| 912 | std.mem.sliceTo(if (dwarf.bin_file.cast(.elf)) |elf_file| sh_name: { | |
| 913 | const zo = elf_file.zigObjectPtr().?; | |
| 914 | const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index; | |
| 915 | break :sh_name elf_file.shstrtab.items[elf_file.sections.items(.shdr)[shndx].sh_name..]; | |
| 916 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| | |
| 897 | 917 | if (macho_file.d_sym) |*d_sym| |
| 898 | 918 | &d_sym.sections.items[sec.index].segname |
| 899 | 919 | else |
| ... | ... | @@ -924,7 +944,7 @@ const Entry = struct { |
| 924 | 944 | } |
| 925 | 945 | |
| 926 | 946 | fn resolveRelocs(entry: *Entry, unit: *Unit, sec: *Section, dwarf: *Dwarf) RelocError!void { |
| 927 | const entry_off = sec.off + unit.off + unit.header_len + entry.off; | |
| 947 | const entry_off = sec.off(dwarf) + unit.off + unit.header_len + entry.off; | |
| 928 | 948 | for (entry.cross_entry_relocs.items) |reloc| { |
| 929 | 949 | try dwarf.resolveReloc( |
| 930 | 950 | entry_off + reloc.source_off, |
| ... | ... | @@ -961,7 +981,8 @@ const Entry = struct { |
| 961 | 981 | .none, .debug_frame => {}, |
| 962 | 982 | .eh_frame => return if (dwarf.bin_file.cast(.elf)) |elf_file| { |
| 963 | 983 | const zo = elf_file.zigObjectPtr().?; |
| 964 | const entry_addr: i64 = @intCast(entry_off - sec.off + elf_file.shdrs.items[sec.index].sh_addr); | |
| 984 | const shndx = zo.symbol(sec.index).atom(elf_file).?.output_section_index; | |
| 985 | const entry_addr: i64 = @intCast(entry_off - sec.off(dwarf) + elf_file.shdrs.items[shndx].sh_addr); | |
| 965 | 986 | for (entry.external_relocs.items) |reloc| { |
| 966 | 987 | const symbol = zo.symbol(reloc.target_sym); |
| 967 | 988 | try dwarf.resolveReloc( |
| ... | ... | @@ -1877,34 +1898,7 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf { |
| 1877 | 1898 | } |
| 1878 | 1899 | |
| 1879 | 1900 | pub fn reloadSectionMetadata(dwarf: *Dwarf) void { |
| 1880 | if (dwarf.bin_file.cast(.elf)) |elf_file| { | |
| 1881 | for ([_]*Section{ | |
| 1882 | &dwarf.debug_abbrev.section, | |
| 1883 | &dwarf.debug_aranges.section, | |
| 1884 | &dwarf.debug_frame.section, | |
| 1885 | &dwarf.debug_info.section, | |
| 1886 | &dwarf.debug_line.section, | |
| 1887 | &dwarf.debug_line_str.section, | |
| 1888 | &dwarf.debug_loclists.section, | |
| 1889 | &dwarf.debug_rnglists.section, | |
| 1890 | &dwarf.debug_str.section, | |
| 1891 | }, [_]u32{ | |
| 1892 | elf_file.debug_abbrev_section_index.?, | |
| 1893 | elf_file.debug_aranges_section_index.?, | |
| 1894 | elf_file.eh_frame_section_index.?, | |
| 1895 | elf_file.debug_info_section_index.?, | |
| 1896 | elf_file.debug_line_section_index.?, | |
| 1897 | elf_file.debug_line_str_section_index.?, | |
| 1898 | elf_file.debug_loclists_section_index.?, | |
| 1899 | elf_file.debug_rnglists_section_index.?, | |
| 1900 | elf_file.debug_str_section_index.?, | |
| 1901 | }) |sec, section_index| { | |
| 1902 | const shdr = &elf_file.sections.items(.shdr)[section_index]; | |
| 1903 | sec.index = section_index; | |
| 1904 | sec.off = shdr.sh_offset; | |
| 1905 | sec.len = shdr.sh_size; | |
| 1906 | } | |
| 1907 | } else if (dwarf.bin_file.cast(.macho)) |macho_file| { | |
| 1901 | if (dwarf.bin_file.cast(.macho)) |macho_file| { | |
| 1908 | 1902 | if (macho_file.d_sym) |*d_sym| { |
| 1909 | 1903 | for ([_]*Section{ |
| 1910 | 1904 | &dwarf.debug_abbrev.section, |
| ... | ... | @@ -1927,7 +1921,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void { |
| 1927 | 1921 | }) |sec, sect_index| { |
| 1928 | 1922 | const header = &d_sym.sections.items[sect_index]; |
| 1929 | 1923 | sec.index = sect_index; |
| 1930 | sec.off = header.offset; | |
| 1931 | 1924 | sec.len = header.size; |
| 1932 | 1925 | } |
| 1933 | 1926 | } else { |
| ... | ... | @@ -1952,7 +1945,6 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void { |
| 1952 | 1945 | }) |sec, sect_index| { |
| 1953 | 1946 | const header = &macho_file.sections.items(.header)[sect_index]; |
| 1954 | 1947 | sec.index = sect_index; |
| 1955 | sec.off = header.offset; | |
| 1956 | 1948 | sec.len = header.size; |
| 1957 | 1949 | } |
| 1958 | 1950 | } |
| ... | ... | @@ -1960,6 +1952,32 @@ pub fn reloadSectionMetadata(dwarf: *Dwarf) void { |
| 1960 | 1952 | } |
| 1961 | 1953 | |
| 1962 | 1954 | pub fn initMetadata(dwarf: *Dwarf) UpdateError!void { |
| 1955 | if (dwarf.bin_file.cast(.elf)) |elf_file| { | |
| 1956 | const zo = elf_file.zigObjectPtr().?; | |
| 1957 | for ([_]*Section{ | |
| 1958 | &dwarf.debug_abbrev.section, | |
| 1959 | &dwarf.debug_aranges.section, | |
| 1960 | &dwarf.debug_frame.section, | |
| 1961 | &dwarf.debug_info.section, | |
| 1962 | &dwarf.debug_line.section, | |
| 1963 | &dwarf.debug_line_str.section, | |
| 1964 | &dwarf.debug_loclists.section, | |
| 1965 | &dwarf.debug_rnglists.section, | |
| 1966 | &dwarf.debug_str.section, | |
| 1967 | }, [_]u32{ | |
| 1968 | zo.debug_abbrev_index.?, | |
| 1969 | zo.debug_aranges_index.?, | |
| 1970 | zo.eh_frame_index.?, | |
| 1971 | zo.debug_info_index.?, | |
| 1972 | zo.debug_line_index.?, | |
| 1973 | zo.debug_line_str_index.?, | |
| 1974 | zo.debug_loclists_index.?, | |
| 1975 | zo.debug_rnglists_index.?, | |
| 1976 | zo.debug_str_index.?, | |
| 1977 | }) |sec, sym_index| { | |
| 1978 | sec.index = sym_index; | |
| 1979 | } | |
| 1980 | } | |
| 1963 | 1981 | dwarf.reloadSectionMetadata(); |
| 1964 | 1982 | |
| 1965 | 1983 | dwarf.debug_abbrev.section.pad_to_ideal = false; |
| ... | ... | @@ -2523,7 +2541,7 @@ pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool |
| 2523 | 2541 | var abbrev_code_buf: [AbbrevCode.decl_bytes]u8 = undefined; |
| 2524 | 2542 | if (try dwarf.getFile().?.preadAll( |
| 2525 | 2543 | &abbrev_code_buf, |
| 2526 | dwarf.debug_info.section.off + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, | |
| 2544 | dwarf.debug_info.section.off(dwarf) + unit_ptr.off + unit_ptr.header_len + entry_ptr.off, | |
| 2527 | 2545 | ) != abbrev_code_buf.len) return error.InputOutput; |
| 2528 | 2546 | var abbrev_code_fbs = std.io.fixedBufferStream(&abbrev_code_buf); |
| 2529 | 2547 | const abbrev_code: AbbrevCode = @enumFromInt( |
| ... | ... | @@ -3934,7 +3952,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { |
| 3934 | 3952 | if (dwarf.debug_str.section.dirty) { |
| 3935 | 3953 | const contents = dwarf.debug_str.contents.items; |
| 3936 | 3954 | try dwarf.debug_str.section.resize(dwarf, contents.len); |
| 3937 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off); | |
| 3955 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_str.section.off(dwarf)); | |
| 3938 | 3956 | dwarf.debug_str.section.dirty = false; |
| 3939 | 3957 | } |
| 3940 | 3958 | if (dwarf.debug_line.section.dirty) { |
| ... | ... | @@ -4040,7 +4058,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { |
| 4040 | 4058 | if (dwarf.debug_line_str.section.dirty) { |
| 4041 | 4059 | const contents = dwarf.debug_line_str.contents.items; |
| 4042 | 4060 | try dwarf.debug_line_str.section.resize(dwarf, contents.len); |
| 4043 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off); | |
| 4061 | try dwarf.getFile().?.pwriteAll(contents, dwarf.debug_line_str.section.off(dwarf)); | |
| 4044 | 4062 | dwarf.debug_line_str.section.dirty = false; |
| 4045 | 4063 | } |
| 4046 | 4064 | if (dwarf.debug_loclists.section.dirty) { |
src/link/Elf.zig+328-293| ... | ... | @@ -54,16 +54,6 @@ shdr_table_offset: ?u64 = null, |
| 54 | 54 | /// Same order as in the file. |
| 55 | 55 | phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{}, |
| 56 | 56 | |
| 57 | /// Tracked loadable segments during incremental linking. | |
| 58 | /// The index into the program headers of a PT_LOAD program header with Read and Execute flags | |
| 59 | phdr_zig_load_re_index: ?u16 = null, | |
| 60 | /// The index into the program headers of a PT_LOAD program header with Read flag | |
| 61 | phdr_zig_load_ro_index: ?u16 = null, | |
| 62 | /// The index into the program headers of a PT_LOAD program header with Write flag | |
| 63 | phdr_zig_load_rw_index: ?u16 = null, | |
| 64 | /// The index into the program headers of a PT_LOAD program header with zerofill data. | |
| 65 | phdr_zig_load_zerofill_index: ?u16 = null, | |
| 66 | ||
| 67 | 57 | /// Special program headers |
| 68 | 58 | /// PT_PHDR |
| 69 | 59 | phdr_table_index: ?u16 = null, |
| ... | ... | @@ -124,22 +114,6 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 124 | 114 | /// Applies only to a relocatable. |
| 125 | 115 | comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, |
| 126 | 116 | |
| 127 | /// Tracked section headers with incremental updates to Zig object. | |
| 128 | /// .rela.* sections are only used when emitting a relocatable object file. | |
| 129 | zig_text_section_index: ?u32 = null, | |
| 130 | zig_data_rel_ro_section_index: ?u32 = null, | |
| 131 | zig_data_section_index: ?u32 = null, | |
| 132 | zig_bss_section_index: ?u32 = null, | |
| 133 | ||
| 134 | debug_info_section_index: ?u32 = null, | |
| 135 | debug_abbrev_section_index: ?u32 = null, | |
| 136 | debug_str_section_index: ?u32 = null, | |
| 137 | debug_aranges_section_index: ?u32 = null, | |
| 138 | debug_line_section_index: ?u32 = null, | |
| 139 | debug_line_str_section_index: ?u32 = null, | |
| 140 | debug_loclists_section_index: ?u32 = null, | |
| 141 | debug_rnglists_section_index: ?u32 = null, | |
| 142 | ||
| 143 | 117 | copy_rel_section_index: ?u32 = null, |
| 144 | 118 | dynamic_section_index: ?u32 = null, |
| 145 | 119 | dynstrtab_section_index: ?u32 = null, |
| ... | ... | @@ -419,7 +393,8 @@ pub fn deinit(self: *Elf) void { |
| 419 | 393 | self.objects.deinit(gpa); |
| 420 | 394 | self.shared_objects.deinit(gpa); |
| 421 | 395 | |
| 422 | for (self.sections.items(.atom_list), self.sections.items(.free_list)) |*atoms, *free_list| { | |
| 396 | for (self.sections.items(.atom_list_2), self.sections.items(.atom_list), self.sections.items(.free_list)) |*atom_list, *atoms, *free_list| { | |
| 397 | atom_list.deinit(gpa); | |
| 423 | 398 | atoms.deinit(gpa); |
| 424 | 399 | free_list.deinit(gpa); |
| 425 | 400 | } |
| ... | ... | @@ -554,7 +529,7 @@ pub fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) !u64 { |
| 554 | 529 | return start; |
| 555 | 530 | } |
| 556 | 531 | |
| 557 | pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { | |
| 532 | pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64, min_alignment: u64) !void { | |
| 558 | 533 | const slice = self.sections.slice(); |
| 559 | 534 | const shdr = &slice.items(.shdr)[shdr_index]; |
| 560 | 535 | assert(shdr.sh_flags & elf.SHF_ALLOC != 0); |
| ... | ... | @@ -573,8 +548,7 @@ pub fn growAllocSection(self: *Elf, shdr_index: u32, needed_size: u64) !void { |
| 573 | 548 | const existing_size = shdr.sh_size; |
| 574 | 549 | shdr.sh_size = 0; |
| 575 | 550 | // Must move the entire section. |
| 576 | const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign; | |
| 577 | const new_offset = try self.findFreeSpace(needed_size, alignment); | |
| 551 | const new_offset = try self.findFreeSpace(needed_size, min_alignment); | |
| 578 | 552 | |
| 579 | 553 | log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{ |
| 580 | 554 | self.getShString(shdr.sh_name), |
| ... | ... | @@ -614,7 +588,7 @@ pub fn growNonAllocSection( |
| 614 | 588 | self: *Elf, |
| 615 | 589 | shdr_index: u32, |
| 616 | 590 | needed_size: u64, |
| 617 | min_alignment: u32, | |
| 591 | min_alignment: u64, | |
| 618 | 592 | requires_file_copy: bool, |
| 619 | 593 | ) !void { |
| 620 | 594 | const shdr = &self.sections.items(.shdr)[shdr_index]; |
| ... | ... | @@ -648,33 +622,124 @@ pub fn growNonAllocSection( |
| 648 | 622 | try self.base.file.?.setEndPos(shdr.sh_offset + needed_size); |
| 649 | 623 | } |
| 650 | 624 | shdr.sh_size = needed_size; |
| 651 | ||
| 652 | 625 | self.markDirty(shdr_index); |
| 653 | 626 | } |
| 654 | 627 | |
| 655 | 628 | pub fn markDirty(self: *Elf, shdr_index: u32) void { |
| 656 | const zig_object = self.zigObjectPtr().?; | |
| 657 | if (zig_object.dwarf) |_| { | |
| 658 | if (self.debug_info_section_index.? == shdr_index) { | |
| 659 | zig_object.debug_info_section_dirty = true; | |
| 660 | } else if (self.debug_abbrev_section_index.? == shdr_index) { | |
| 661 | zig_object.debug_abbrev_section_dirty = true; | |
| 662 | } else if (self.debug_str_section_index.? == shdr_index) { | |
| 663 | zig_object.debug_str_section_dirty = true; | |
| 664 | } else if (self.debug_aranges_section_index.? == shdr_index) { | |
| 665 | zig_object.debug_aranges_section_dirty = true; | |
| 666 | } else if (self.debug_line_section_index.? == shdr_index) { | |
| 667 | zig_object.debug_line_section_dirty = true; | |
| 668 | } else if (self.debug_line_str_section_index.? == shdr_index) { | |
| 669 | zig_object.debug_line_str_section_dirty = true; | |
| 670 | } else if (self.debug_loclists_section_index.? == shdr_index) { | |
| 671 | zig_object.debug_loclists_section_dirty = true; | |
| 672 | } else if (self.debug_rnglists_section_index.? == shdr_index) { | |
| 673 | zig_object.debug_rnglists_section_dirty = true; | |
| 629 | if (self.zigObjectPtr()) |zo| { | |
| 630 | for ([_]?Symbol.Index{ | |
| 631 | zo.debug_info_index, | |
| 632 | zo.debug_abbrev_index, | |
| 633 | zo.debug_aranges_index, | |
| 634 | zo.debug_str_index, | |
| 635 | zo.debug_line_index, | |
| 636 | zo.debug_line_str_index, | |
| 637 | zo.debug_loclists_index, | |
| 638 | zo.debug_rnglists_index, | |
| 639 | }, [_]*bool{ | |
| 640 | &zo.debug_info_section_dirty, | |
| 641 | &zo.debug_abbrev_section_dirty, | |
| 642 | &zo.debug_aranges_section_dirty, | |
| 643 | &zo.debug_str_section_dirty, | |
| 644 | &zo.debug_line_section_dirty, | |
| 645 | &zo.debug_line_str_section_dirty, | |
| 646 | &zo.debug_loclists_section_dirty, | |
| 647 | &zo.debug_rnglists_section_dirty, | |
| 648 | }) |maybe_sym_index, dirty| { | |
| 649 | const sym_index = maybe_sym_index orelse continue; | |
| 650 | if (zo.symbol(sym_index).atom(self).?.output_section_index == shdr_index) { | |
| 651 | dirty.* = true; | |
| 652 | break; | |
| 653 | } | |
| 674 | 654 | } |
| 675 | 655 | } |
| 676 | 656 | } |
| 677 | 657 | |
| 658 | const AllocateChunkResult = struct { | |
| 659 | value: u64, | |
| 660 | placement: Ref, | |
| 661 | }; | |
| 662 | ||
| 663 | pub fn allocateChunk(self: *Elf, args: struct { | |
| 664 | size: u64, | |
| 665 | shndx: u32, | |
| 666 | alignment: Atom.Alignment, | |
| 667 | requires_padding: bool = true, | |
| 668 | }) !AllocateChunkResult { | |
| 669 | const slice = self.sections.slice(); | |
| 670 | const shdr = &slice.items(.shdr)[args.shndx]; | |
| 671 | const free_list = &slice.items(.free_list)[args.shndx]; | |
| 672 | const last_atom_ref = &slice.items(.last_atom)[args.shndx]; | |
| 673 | const new_atom_ideal_capacity = if (args.requires_padding) padToIdeal(args.size) else args.size; | |
| 674 | ||
| 675 | // First we look for an appropriately sized free list node. | |
| 676 | // The list is unordered. We'll just take the first thing that works. | |
| 677 | const res: AllocateChunkResult = blk: { | |
| 678 | var i: usize = if (self.base.child_pid == null) 0 else free_list.items.len; | |
| 679 | while (i < free_list.items.len) { | |
| 680 | const big_atom_ref = free_list.items[i]; | |
| 681 | const big_atom = self.atom(big_atom_ref).?; | |
| 682 | // We now have a pointer to a live atom that has too much capacity. | |
| 683 | // Is it enough that we could fit this new atom? | |
| 684 | const cap = big_atom.capacity(self); | |
| 685 | const ideal_capacity = if (args.requires_padding) padToIdeal(cap) else cap; | |
| 686 | const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; | |
| 687 | const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; | |
| 688 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | |
| 689 | const new_start_vaddr = args.alignment.backward(new_start_vaddr_unaligned); | |
| 690 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | |
| 691 | // Additional bookkeeping here to notice if this free list node | |
| 692 | // should be deleted because the block that it points to has grown to take up | |
| 693 | // more of the extra capacity. | |
| 694 | if (!big_atom.freeListEligible(self)) { | |
| 695 | _ = free_list.swapRemove(i); | |
| 696 | } else { | |
| 697 | i += 1; | |
| 698 | } | |
| 699 | continue; | |
| 700 | } | |
| 701 | // At this point we know that we will place the new block here. But the | |
| 702 | // remaining question is whether there is still yet enough capacity left | |
| 703 | // over for there to still be a free list node. | |
| 704 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; | |
| 705 | const keep_free_list_node = remaining_capacity >= min_text_capacity; | |
| 706 | ||
| 707 | if (!keep_free_list_node) { | |
| 708 | _ = free_list.swapRemove(i); | |
| 709 | } | |
| 710 | break :blk .{ .value = new_start_vaddr, .placement = big_atom_ref }; | |
| 711 | } else if (self.atom(last_atom_ref.*)) |last_atom| { | |
| 712 | const ideal_capacity = if (args.requires_padding) padToIdeal(last_atom.size) else last_atom.size; | |
| 713 | const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity; | |
| 714 | const new_start_vaddr = args.alignment.forward(ideal_capacity_end_vaddr); | |
| 715 | break :blk .{ .value = new_start_vaddr, .placement = last_atom.ref() }; | |
| 716 | } else { | |
| 717 | break :blk .{ .value = 0, .placement = .{} }; | |
| 718 | } | |
| 719 | }; | |
| 720 | ||
| 721 | log.debug("allocated chunk (size({x}),align({x})) at 0x{x} (file(0x{x}))", .{ | |
| 722 | args.size, | |
| 723 | args.alignment.toByteUnits().?, | |
| 724 | shdr.sh_addr + res.value, | |
| 725 | shdr.sh_offset + res.value, | |
| 726 | }); | |
| 727 | ||
| 728 | const expand_section = if (self.atom(res.placement)) |placement_atom| | |
| 729 | placement_atom.nextAtom(self) == null | |
| 730 | else | |
| 731 | true; | |
| 732 | if (expand_section) { | |
| 733 | const needed_size = res.value + args.size; | |
| 734 | if (shdr.sh_flags & elf.SHF_ALLOC != 0) | |
| 735 | try self.growAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?) | |
| 736 | else | |
| 737 | try self.growNonAllocSection(args.shndx, needed_size, args.alignment.toByteUnits().?, true); | |
| 738 | } | |
| 739 | ||
| 740 | return res; | |
| 741 | } | |
| 742 | ||
| 678 | 743 | pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { |
| 679 | 744 | const use_lld = build_options.have_llvm and self.base.comp.config.use_lld; |
| 680 | 745 | if (use_lld) { |
| ... | ... | @@ -972,14 +1037,13 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 972 | 1037 | try self.initSyntheticSections(); |
| 973 | 1038 | try self.initSpecialPhdrs(); |
| 974 | 1039 | try self.sortShdrs(); |
| 975 | for (self.objects.items) |index| { | |
| 976 | try self.file(index).?.object.addAtomsToOutputSections(self); | |
| 977 | } | |
| 978 | try self.sortInitFini(); | |
| 1040 | ||
| 979 | 1041 | try self.setDynamicSection(rpath_table.keys()); |
| 980 | 1042 | self.sortDynamicSymtab(); |
| 981 | 1043 | try self.setHashSections(); |
| 982 | 1044 | try self.setVersionSymtab(); |
| 1045 | ||
| 1046 | try self.sortInitFini(); | |
| 983 | 1047 | try self.updateMergeSectionSizes(); |
| 984 | 1048 | try self.updateSectionSizes(); |
| 985 | 1049 | |
| ... | ... | @@ -1010,7 +1074,7 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 1010 | 1074 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1011 | 1075 | const code = try zo.codeAlloc(self, atom_index); |
| 1012 | 1076 | defer gpa.free(code); |
| 1013 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 1077 | const file_offset = atom_ptr.offset(self); | |
| 1014 | 1078 | atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) { |
| 1015 | 1079 | error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, |
| 1016 | 1080 | error.UnsupportedCpuArch => { |
| ... | ... | @@ -1750,6 +1814,59 @@ fn scanRelocs(self: *Elf) !void { |
| 1750 | 1814 | } |
| 1751 | 1815 | } |
| 1752 | 1816 | |
| 1817 | pub fn initOutputSection(self: *Elf, args: struct { | |
| 1818 | name: [:0]const u8, | |
| 1819 | flags: u64, | |
| 1820 | type: u32, | |
| 1821 | }) error{OutOfMemory}!u32 { | |
| 1822 | const name = blk: { | |
| 1823 | if (self.base.isRelocatable()) break :blk args.name; | |
| 1824 | if (args.flags & elf.SHF_MERGE != 0) break :blk args.name; | |
| 1825 | const name_prefixes: []const [:0]const u8 = &.{ | |
| 1826 | ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", | |
| 1827 | ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", | |
| 1828 | ".dtors", ".gnu.warning", | |
| 1829 | }; | |
| 1830 | inline for (name_prefixes) |prefix| { | |
| 1831 | if (std.mem.eql(u8, args.name, prefix) or std.mem.startsWith(u8, args.name, prefix ++ ".")) { | |
| 1832 | break :blk prefix; | |
| 1833 | } | |
| 1834 | } | |
| 1835 | break :blk args.name; | |
| 1836 | }; | |
| 1837 | const @"type" = tt: { | |
| 1838 | if (self.getTarget().cpu.arch == .x86_64 and args.type == elf.SHT_X86_64_UNWIND) | |
| 1839 | break :tt elf.SHT_PROGBITS; | |
| 1840 | switch (args.type) { | |
| 1841 | elf.SHT_NULL => unreachable, | |
| 1842 | elf.SHT_PROGBITS => { | |
| 1843 | if (std.mem.eql(u8, args.name, ".init_array") or std.mem.startsWith(u8, args.name, ".init_array.")) | |
| 1844 | break :tt elf.SHT_INIT_ARRAY; | |
| 1845 | if (std.mem.eql(u8, args.name, ".fini_array") or std.mem.startsWith(u8, args.name, ".fini_array.")) | |
| 1846 | break :tt elf.SHT_FINI_ARRAY; | |
| 1847 | break :tt args.type; | |
| 1848 | }, | |
| 1849 | else => break :tt args.type, | |
| 1850 | } | |
| 1851 | }; | |
| 1852 | const flags = blk: { | |
| 1853 | var flags = args.flags; | |
| 1854 | if (!self.base.isRelocatable()) { | |
| 1855 | flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); | |
| 1856 | } | |
| 1857 | break :blk switch (@"type") { | |
| 1858 | elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, | |
| 1859 | else => flags, | |
| 1860 | }; | |
| 1861 | }; | |
| 1862 | const out_shndx = self.sectionByName(name) orelse try self.addSection(.{ | |
| 1863 | .type = @"type", | |
| 1864 | .flags = flags, | |
| 1865 | .name = try self.insertShString(name), | |
| 1866 | }); | |
| 1867 | return out_shndx; | |
| 1868 | } | |
| 1869 | ||
| 1753 | 1870 | fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void { |
| 1754 | 1871 | dev.check(.lld_linker); |
| 1755 | 1872 | |
| ... | ... | @@ -2783,12 +2900,16 @@ fn initSyntheticSections(self: *Elf) !void { |
| 2783 | 2900 | const target = self.getTarget(); |
| 2784 | 2901 | const ptr_size = self.ptrWidthBytes(); |
| 2785 | 2902 | |
| 2786 | const needs_eh_frame = for (self.objects.items) |index| { | |
| 2787 | if (self.file(index).?.object.cies.items.len > 0) break true; | |
| 2788 | } else false; | |
| 2903 | const needs_eh_frame = blk: { | |
| 2904 | if (self.zigObjectPtr()) |zo| | |
| 2905 | if (zo.eh_frame_index != null) break :blk true; | |
| 2906 | break :blk for (self.objects.items) |index| { | |
| 2907 | if (self.file(index).?.object.cies.items.len > 0) break true; | |
| 2908 | } else false; | |
| 2909 | }; | |
| 2789 | 2910 | if (needs_eh_frame) { |
| 2790 | 2911 | if (self.eh_frame_section_index == null) { |
| 2791 | self.eh_frame_section_index = try self.addSection(.{ | |
| 2912 | self.eh_frame_section_index = self.sectionByName(".eh_frame") orelse try self.addSection(.{ | |
| 2792 | 2913 | .name = try self.insertShString(".eh_frame"), |
| 2793 | 2914 | .type = if (target.cpu.arch == .x86_64) |
| 2794 | 2915 | elf.SHT_X86_64_UNWIND |
| ... | ... | @@ -3084,8 +3205,9 @@ fn sortInitFini(self: *Elf) !void { |
| 3084 | 3205 | } |
| 3085 | 3206 | }; |
| 3086 | 3207 | |
| 3087 | for (slice.items(.shdr), slice.items(.atom_list)) |shdr, *atom_list| { | |
| 3208 | for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| { | |
| 3088 | 3209 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 3210 | if (atom_list.atoms.items.len == 0) continue; | |
| 3089 | 3211 | |
| 3090 | 3212 | var is_init_fini = false; |
| 3091 | 3213 | var is_ctor_dtor = false; |
| ... | ... | @@ -3099,15 +3221,13 @@ fn sortInitFini(self: *Elf) !void { |
| 3099 | 3221 | is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null; |
| 3100 | 3222 | }, |
| 3101 | 3223 | } |
| 3102 | ||
| 3103 | 3224 | if (!is_init_fini and !is_ctor_dtor) continue; |
| 3104 | if (atom_list.items.len == 0) continue; | |
| 3105 | 3225 | |
| 3106 | 3226 | var entries = std.ArrayList(Entry).init(gpa); |
| 3107 | try entries.ensureTotalCapacityPrecise(atom_list.items.len); | |
| 3227 | try entries.ensureTotalCapacityPrecise(atom_list.atoms.items.len); | |
| 3108 | 3228 | defer entries.deinit(); |
| 3109 | 3229 | |
| 3110 | for (atom_list.items) |ref| { | |
| 3230 | for (atom_list.atoms.items) |ref| { | |
| 3111 | 3231 | const atom_ptr = self.atom(ref).?; |
| 3112 | 3232 | const object = atom_ptr.file(self).?.object; |
| 3113 | 3233 | const priority = blk: { |
| ... | ... | @@ -3126,9 +3246,9 @@ fn sortInitFini(self: *Elf) !void { |
| 3126 | 3246 | |
| 3127 | 3247 | mem.sort(Entry, entries.items, self, Entry.lessThan); |
| 3128 | 3248 | |
| 3129 | atom_list.clearRetainingCapacity(); | |
| 3249 | atom_list.atoms.clearRetainingCapacity(); | |
| 3130 | 3250 | for (entries.items) |entry| { |
| 3131 | atom_list.appendAssumeCapacity(entry.atom_ref); | |
| 3251 | atom_list.atoms.appendAssumeCapacity(entry.atom_ref); | |
| 3132 | 3252 | } |
| 3133 | 3253 | } |
| 3134 | 3254 | } |
| ... | ... | @@ -3233,9 +3353,6 @@ fn sortPhdrs(self: *Elf) error{OutOfMemory}!void { |
| 3233 | 3353 | } |
| 3234 | 3354 | |
| 3235 | 3355 | for (&[_]*?u16{ |
| 3236 | &self.phdr_zig_load_re_index, | |
| 3237 | &self.phdr_zig_load_ro_index, | |
| 3238 | &self.phdr_zig_load_zerofill_index, | |
| 3239 | 3356 | &self.phdr_table_index, |
| 3240 | 3357 | &self.phdr_table_load_index, |
| 3241 | 3358 | &self.phdr_interp_index, |
| ... | ... | @@ -3272,33 +3389,36 @@ fn shdrRank(self: *Elf, shndx: u32) u8 { |
| 3272 | 3389 | elf.SHT_PREINIT_ARRAY, |
| 3273 | 3390 | elf.SHT_INIT_ARRAY, |
| 3274 | 3391 | elf.SHT_FINI_ARRAY, |
| 3275 | => return 0xf2, | |
| 3392 | => return 0xf1, | |
| 3276 | 3393 | |
| 3277 | elf.SHT_DYNAMIC => return 0xf3, | |
| 3394 | elf.SHT_DYNAMIC => return 0xf2, | |
| 3278 | 3395 | |
| 3279 | 3396 | elf.SHT_RELA, elf.SHT_GROUP => return 0xf, |
| 3280 | 3397 | |
| 3281 | 3398 | elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { |
| 3282 | 3399 | if (flags & elf.SHF_EXECINSTR != 0) { |
| 3283 | return 0xf1; | |
| 3400 | return 0xf0; | |
| 3284 | 3401 | } else if (flags & elf.SHF_WRITE != 0) { |
| 3285 | return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6; | |
| 3402 | return if (flags & elf.SHF_TLS != 0) 0xf3 else 0xf5; | |
| 3286 | 3403 | } else if (mem.eql(u8, name, ".interp")) { |
| 3287 | 3404 | return 1; |
| 3405 | } else if (mem.startsWith(u8, name, ".eh_frame")) { | |
| 3406 | return 0xe1; | |
| 3288 | 3407 | } else { |
| 3289 | return 0xf0; | |
| 3408 | return 0xe0; | |
| 3290 | 3409 | } |
| 3291 | 3410 | } else { |
| 3292 | 3411 | if (mem.startsWith(u8, name, ".debug")) { |
| 3293 | return 0xf8; | |
| 3412 | return 0xf7; | |
| 3294 | 3413 | } else { |
| 3295 | return 0xf9; | |
| 3414 | return 0xf8; | |
| 3296 | 3415 | } |
| 3297 | 3416 | }, |
| 3417 | elf.SHT_X86_64_UNWIND => return 0xe1, | |
| 3298 | 3418 | |
| 3299 | elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7, | |
| 3300 | elf.SHT_SYMTAB => return 0xfa, | |
| 3301 | elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb, | |
| 3419 | elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6, | |
| 3420 | elf.SHT_SYMTAB => return 0xf9, | |
| 3421 | elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfa, | |
| 3302 | 3422 | else => return 0xff, |
| 3303 | 3423 | } |
| 3304 | 3424 | } |
| ... | ... | @@ -3361,18 +3481,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { |
| 3361 | 3481 | &self.copy_rel_section_index, |
| 3362 | 3482 | &self.versym_section_index, |
| 3363 | 3483 | &self.verneed_section_index, |
| 3364 | &self.zig_text_section_index, | |
| 3365 | &self.zig_data_rel_ro_section_index, | |
| 3366 | &self.zig_data_section_index, | |
| 3367 | &self.zig_bss_section_index, | |
| 3368 | &self.debug_info_section_index, | |
| 3369 | &self.debug_abbrev_section_index, | |
| 3370 | &self.debug_str_section_index, | |
| 3371 | &self.debug_aranges_section_index, | |
| 3372 | &self.debug_line_section_index, | |
| 3373 | &self.debug_line_str_section_index, | |
| 3374 | &self.debug_loclists_section_index, | |
| 3375 | &self.debug_rnglists_section_index, | |
| 3376 | 3484 | }) |maybe_index| { |
| 3377 | 3485 | if (maybe_index.*) |*index| { |
| 3378 | 3486 | index.* = backlinks[index.*]; |
| ... | ... | @@ -3383,13 +3491,19 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { |
| 3383 | 3491 | msec.output_section_index = backlinks[msec.output_section_index]; |
| 3384 | 3492 | } |
| 3385 | 3493 | |
| 3386 | for (self.sections.items(.shdr)) |*shdr| { | |
| 3387 | if (shdr.sh_type != elf.SHT_RELA) continue; | |
| 3388 | // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections | |
| 3389 | // to point at symtab | |
| 3390 | // shdr.sh_link = backlinks[shdr.sh_link]; | |
| 3391 | shdr.sh_link = self.symtab_section_index.?; | |
| 3392 | shdr.sh_info = backlinks[shdr.sh_info]; | |
| 3494 | const slice = self.sections.slice(); | |
| 3495 | for (slice.items(.shdr), slice.items(.atom_list_2)) |*shdr, *atom_list| { | |
| 3496 | atom_list.output_section_index = backlinks[atom_list.output_section_index]; | |
| 3497 | for (atom_list.atoms.items) |ref| { | |
| 3498 | self.atom(ref).?.output_section_index = atom_list.output_section_index; | |
| 3499 | } | |
| 3500 | if (shdr.sh_type == elf.SHT_RELA) { | |
| 3501 | // FIXME:JK we should spin up .symtab potentially earlier, or set all non-dynamic RELA sections | |
| 3502 | // to point at symtab | |
| 3503 | // shdr.sh_link = backlinks[shdr.sh_link]; | |
| 3504 | shdr.sh_link = self.symtab_section_index.?; | |
| 3505 | shdr.sh_info = backlinks[shdr.sh_info]; | |
| 3506 | } | |
| 3393 | 3507 | } |
| 3394 | 3508 | |
| 3395 | 3509 | if (self.zigObjectPtr()) |zo| { |
| ... | ... | @@ -3397,7 +3511,6 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { |
| 3397 | 3511 | const atom_ptr = zo.atom(atom_index) orelse continue; |
| 3398 | 3512 | atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index]; |
| 3399 | 3513 | } |
| 3400 | if (zo.dwarf) |*dwarf| dwarf.reloadSectionMetadata(); | |
| 3401 | 3514 | } |
| 3402 | 3515 | |
| 3403 | 3516 | for (self.comdat_group_sections.items) |*cg| { |
| ... | ... | @@ -3405,53 +3518,53 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { |
| 3405 | 3518 | } |
| 3406 | 3519 | |
| 3407 | 3520 | if (self.symtab_section_index) |index| { |
| 3408 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3521 | const shdr = &slice.items(.shdr)[index]; | |
| 3409 | 3522 | shdr.sh_link = self.strtab_section_index.?; |
| 3410 | 3523 | } |
| 3411 | 3524 | |
| 3412 | 3525 | if (self.dynamic_section_index) |index| { |
| 3413 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3526 | const shdr = &slice.items(.shdr)[index]; | |
| 3414 | 3527 | shdr.sh_link = self.dynstrtab_section_index.?; |
| 3415 | 3528 | } |
| 3416 | 3529 | |
| 3417 | 3530 | if (self.dynsymtab_section_index) |index| { |
| 3418 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3531 | const shdr = &slice.items(.shdr)[index]; | |
| 3419 | 3532 | shdr.sh_link = self.dynstrtab_section_index.?; |
| 3420 | 3533 | } |
| 3421 | 3534 | |
| 3422 | 3535 | if (self.hash_section_index) |index| { |
| 3423 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3536 | const shdr = &slice.items(.shdr)[index]; | |
| 3424 | 3537 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3425 | 3538 | } |
| 3426 | 3539 | |
| 3427 | 3540 | if (self.gnu_hash_section_index) |index| { |
| 3428 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3541 | const shdr = &slice.items(.shdr)[index]; | |
| 3429 | 3542 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3430 | 3543 | } |
| 3431 | 3544 | |
| 3432 | 3545 | if (self.versym_section_index) |index| { |
| 3433 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3546 | const shdr = &slice.items(.shdr)[index]; | |
| 3434 | 3547 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3435 | 3548 | } |
| 3436 | 3549 | |
| 3437 | 3550 | if (self.verneed_section_index) |index| { |
| 3438 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3551 | const shdr = &slice.items(.shdr)[index]; | |
| 3439 | 3552 | shdr.sh_link = self.dynstrtab_section_index.?; |
| 3440 | 3553 | } |
| 3441 | 3554 | |
| 3442 | 3555 | if (self.rela_dyn_section_index) |index| { |
| 3443 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3556 | const shdr = &slice.items(.shdr)[index]; | |
| 3444 | 3557 | shdr.sh_link = self.dynsymtab_section_index orelse 0; |
| 3445 | 3558 | } |
| 3446 | 3559 | |
| 3447 | 3560 | if (self.rela_plt_section_index) |index| { |
| 3448 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3561 | const shdr = &slice.items(.shdr)[index]; | |
| 3449 | 3562 | shdr.sh_link = self.dynsymtab_section_index.?; |
| 3450 | 3563 | shdr.sh_info = self.plt_section_index.?; |
| 3451 | 3564 | } |
| 3452 | 3565 | |
| 3453 | 3566 | if (self.eh_frame_rela_section_index) |index| { |
| 3454 | const shdr = &self.sections.items(.shdr)[index]; | |
| 3567 | const shdr = &slice.items(.shdr)[index]; | |
| 3455 | 3568 | shdr.sh_link = self.symtab_section_index.?; |
| 3456 | 3569 | shdr.sh_info = self.eh_frame_section_index.?; |
| 3457 | 3570 | } |
| ... | ... | @@ -3459,37 +3572,32 @@ fn resetShdrIndexes(self: *Elf, backlinks: []const u32) void { |
| 3459 | 3572 | |
| 3460 | 3573 | fn updateSectionSizes(self: *Elf) !void { |
| 3461 | 3574 | const slice = self.sections.slice(); |
| 3462 | for (slice.items(.shdr), slice.items(.atom_list)) |*shdr, atom_list| { | |
| 3463 | if (atom_list.items.len == 0) continue; | |
| 3575 | for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| { | |
| 3576 | if (atom_list.atoms.items.len == 0) continue; | |
| 3464 | 3577 | if (self.requiresThunks() and shdr.sh_flags & elf.SHF_EXECINSTR != 0) continue; |
| 3465 | for (atom_list.items) |ref| { | |
| 3466 | const atom_ptr = self.atom(ref) orelse continue; | |
| 3467 | if (!atom_ptr.alive) continue; | |
| 3468 | const offset = atom_ptr.alignment.forward(shdr.sh_size); | |
| 3469 | const padding = offset - shdr.sh_size; | |
| 3470 | atom_ptr.value = @intCast(offset); | |
| 3471 | shdr.sh_size += padding + atom_ptr.size; | |
| 3472 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); | |
| 3473 | } | |
| 3578 | atom_list.updateSize(self); | |
| 3579 | try atom_list.allocate(self); | |
| 3474 | 3580 | } |
| 3475 | 3581 | |
| 3476 | 3582 | if (self.requiresThunks()) { |
| 3477 | for (slice.items(.shdr), slice.items(.atom_list), 0..) |*shdr, atom_list, shndx| { | |
| 3583 | for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, *atom_list| { | |
| 3478 | 3584 | if (shdr.sh_flags & elf.SHF_EXECINSTR == 0) continue; |
| 3479 | if (atom_list.items.len == 0) continue; | |
| 3585 | if (atom_list.atoms.items.len == 0) continue; | |
| 3480 | 3586 | |
| 3481 | 3587 | // Create jump/branch range extenders if needed. |
| 3482 | try self.createThunks(shdr, @intCast(shndx)); | |
| 3588 | try self.createThunks(atom_list); | |
| 3589 | try atom_list.allocate(self); | |
| 3590 | } | |
| 3591 | ||
| 3592 | // FIXME:JK this will hopefully not be needed once we create a link from Atom/Thunk to AtomList. | |
| 3593 | for (self.thunks.items) |*th| { | |
| 3594 | th.value += slice.items(.atom_list_2)[th.output_section_index].value; | |
| 3483 | 3595 | } |
| 3484 | 3596 | } |
| 3485 | 3597 | |
| 3486 | 3598 | const shdrs = slice.items(.shdr); |
| 3487 | 3599 | if (self.eh_frame_section_index) |index| { |
| 3488 | shdrs[index].sh_size = existing_size: { | |
| 3489 | const zo = self.zigObjectPtr() orelse break :existing_size 0; | |
| 3490 | const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); | |
| 3491 | break :existing_size sym.atom(self).?.size; | |
| 3492 | } + try eh_frame.calcEhFrameSize(self); | |
| 3600 | shdrs[index].sh_size = try eh_frame.calcEhFrameSize(self); | |
| 3493 | 3601 | } |
| 3494 | 3602 | |
| 3495 | 3603 | if (self.eh_frame_hdr_section_index) |index| { |
| ... | ... | @@ -3587,13 +3695,11 @@ fn shdrToPhdrFlags(sh_flags: u64) u32 { |
| 3587 | 3695 | /// (This is an upper bound so that we can reserve enough space for the header and progam header |
| 3588 | 3696 | /// table without running out of space and being forced to move things around.) |
| 3589 | 3697 | fn getMaxNumberOfPhdrs() u64 { |
| 3590 | // First, assume we compile Zig's source incrementally, this gives us: | |
| 3591 | var num: u64 = number_of_zig_segments; | |
| 3592 | // Next, the estimated maximum number of segments the linker can emit for input sections are: | |
| 3593 | num += max_number_of_object_segments; | |
| 3594 | // Next, any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP: | |
| 3698 | // The estimated maximum number of segments the linker can emit for input sections are: | |
| 3699 | var num: u64 = max_number_of_object_segments; | |
| 3700 | // Any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP: | |
| 3595 | 3701 | num += max_number_of_special_phdrs; |
| 3596 | // Finally, PHDR program header and corresponding read-only load segment: | |
| 3702 | // PHDR program header and corresponding read-only load segment: | |
| 3597 | 3703 | num += 2; |
| 3598 | 3704 | return num; |
| 3599 | 3705 | } |
| ... | ... | @@ -3603,10 +3709,9 @@ fn getMaxNumberOfPhdrs() u64 { |
| 3603 | 3709 | /// We permit a maximum of 3**2 number of segments. |
| 3604 | 3710 | fn calcNumberOfSegments(self: *Elf) usize { |
| 3605 | 3711 | var covers: [9]bool = [_]bool{false} ** 9; |
| 3606 | for (self.sections.items(.shdr), 0..) |shdr, shndx| { | |
| 3712 | for (self.sections.items(.shdr)) |shdr| { | |
| 3607 | 3713 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 3608 | 3714 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 3609 | if (self.isZigSection(@intCast(shndx))) continue; | |
| 3610 | 3715 | const flags = shdrToPhdrFlags(shdr.sh_flags); |
| 3611 | 3716 | covers[flags - 1] = true; |
| 3612 | 3717 | } |
| ... | ... | @@ -3704,7 +3809,6 @@ pub fn allocateAllocSections(self: *Elf) !void { |
| 3704 | 3809 | for (slice.items(.shdr), 0..) |shdr, shndx| { |
| 3705 | 3810 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 3706 | 3811 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 3707 | if (self.isZigSection(@intCast(shndx))) continue; | |
| 3708 | 3812 | const flags = shdrToPhdrFlags(shdr.sh_flags); |
| 3709 | 3813 | try covers[flags - 1].append(@intCast(shndx)); |
| 3710 | 3814 | } |
| ... | ... | @@ -3794,10 +3898,20 @@ pub fn allocateAllocSections(self: *Elf) !void { |
| 3794 | 3898 | } |
| 3795 | 3899 | new_offset = alignment.@"align"(shndx, shdr.sh_addralign, new_offset); |
| 3796 | 3900 | |
| 3797 | if (shndx == self.eh_frame_section_index) eh_frame: { | |
| 3798 | const zo = self.zigObjectPtr() orelse break :eh_frame; | |
| 3799 | const sym = zo.symbol(zo.eh_frame_index orelse break :eh_frame); | |
| 3800 | const existing_size = sym.atom(self).?.size; | |
| 3901 | if (self.zigObjectPtr()) |zo| blk: { | |
| 3902 | const existing_size = for ([_]?Symbol.Index{ | |
| 3903 | zo.text_index, | |
| 3904 | zo.rodata_index, | |
| 3905 | zo.data_relro_index, | |
| 3906 | zo.data_index, | |
| 3907 | zo.tdata_index, | |
| 3908 | zo.eh_frame_index, | |
| 3909 | }) |maybe_sym_index| { | |
| 3910 | const sect_sym_index = maybe_sym_index orelse continue; | |
| 3911 | const sect_atom_ptr = zo.symbol(sect_sym_index).atom(self).?; | |
| 3912 | if (sect_atom_ptr.output_section_index != shndx) continue; | |
| 3913 | break sect_atom_ptr.size; | |
| 3914 | } else break :blk; | |
| 3801 | 3915 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ |
| 3802 | 3916 | self.getShString(shdr.sh_name), |
| 3803 | 3917 | shdr.sh_offset, |
| ... | ... | @@ -3830,27 +3944,27 @@ pub fn allocateNonAllocSections(self: *Elf) !void { |
| 3830 | 3944 | shdr.sh_size = 0; |
| 3831 | 3945 | const new_offset = try self.findFreeSpace(needed_size, shdr.sh_addralign); |
| 3832 | 3946 | |
| 3833 | if (self.isDebugSection(@intCast(shndx))) { | |
| 3947 | if (self.zigObjectPtr()) |zo| blk: { | |
| 3948 | const existing_size = for ([_]?Symbol.Index{ | |
| 3949 | zo.debug_info_index, | |
| 3950 | zo.debug_abbrev_index, | |
| 3951 | zo.debug_aranges_index, | |
| 3952 | zo.debug_str_index, | |
| 3953 | zo.debug_line_index, | |
| 3954 | zo.debug_line_str_index, | |
| 3955 | zo.debug_loclists_index, | |
| 3956 | zo.debug_rnglists_index, | |
| 3957 | }) |maybe_sym_index| { | |
| 3958 | const sym_index = maybe_sym_index orelse continue; | |
| 3959 | const sym = zo.symbol(sym_index); | |
| 3960 | const atom_ptr = sym.atom(self).?; | |
| 3961 | if (atom_ptr.output_section_index == shndx) break atom_ptr.size; | |
| 3962 | } else break :blk; | |
| 3834 | 3963 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ |
| 3835 | 3964 | self.getShString(shdr.sh_name), |
| 3836 | 3965 | shdr.sh_offset, |
| 3837 | 3966 | new_offset, |
| 3838 | 3967 | }); |
| 3839 | const zo = self.zigObjectPtr().?; | |
| 3840 | const existing_size = for ([_]Symbol.Index{ | |
| 3841 | zo.debug_info_index.?, | |
| 3842 | zo.debug_abbrev_index.?, | |
| 3843 | zo.debug_aranges_index.?, | |
| 3844 | zo.debug_str_index.?, | |
| 3845 | zo.debug_line_index.?, | |
| 3846 | zo.debug_line_str_index.?, | |
| 3847 | zo.debug_loclists_index.?, | |
| 3848 | zo.debug_rnglists_index.?, | |
| 3849 | }) |sym_index| { | |
| 3850 | const sym = zo.symbol(sym_index); | |
| 3851 | const atom_ptr = sym.atom(self).?; | |
| 3852 | if (atom_ptr.output_section_index == shndx) break atom_ptr.size; | |
| 3853 | } else 0; | |
| 3854 | 3968 | const amt = try self.base.file.?.copyRangeAll( |
| 3855 | 3969 | shdr.sh_offset, |
| 3856 | 3970 | self.base.file.?, |
| ... | ... | @@ -3934,91 +4048,28 @@ fn writeAtoms(self: *Elf) !void { |
| 3934 | 4048 | undefs.deinit(); |
| 3935 | 4049 | } |
| 3936 | 4050 | |
| 3937 | var has_reloc_errors = false; | |
| 4051 | var buffer = std.ArrayList(u8).init(gpa); | |
| 4052 | defer buffer.deinit(); | |
| 4053 | ||
| 3938 | 4054 | const slice = self.sections.slice(); |
| 3939 | for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { | |
| 3940 | if (shdr.sh_type == elf.SHT_NULL) continue; | |
| 4055 | var has_reloc_errors = false; | |
| 4056 | for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| { | |
| 3941 | 4057 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 3942 | if (atom_list.items.len == 0) continue; | |
| 3943 | ||
| 3944 | log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); | |
| 3945 | ||
| 3946 | // TODO really, really handle debug section separately | |
| 3947 | const base_offset = if (self.isDebugSection(@intCast(shndx))) base_offset: { | |
| 3948 | const zo = self.zigObjectPtr().?; | |
| 3949 | for ([_]Symbol.Index{ | |
| 3950 | zo.debug_info_index.?, | |
| 3951 | zo.debug_abbrev_index.?, | |
| 3952 | zo.debug_aranges_index.?, | |
| 3953 | zo.debug_str_index.?, | |
| 3954 | zo.debug_line_index.?, | |
| 3955 | zo.debug_line_str_index.?, | |
| 3956 | zo.debug_loclists_index.?, | |
| 3957 | zo.debug_rnglists_index.?, | |
| 3958 | }) |sym_index| { | |
| 3959 | const sym = zo.symbol(sym_index); | |
| 3960 | const atom_ptr = sym.atom(self).?; | |
| 3961 | if (atom_ptr.output_section_index == shndx) break :base_offset atom_ptr.size; | |
| 3962 | } | |
| 3963 | break :base_offset 0; | |
| 3964 | } else if (@as(u32, @intCast(shndx)) == self.eh_frame_section_index) base_offset: { | |
| 3965 | const zo = self.zigObjectPtr() orelse break :base_offset 0; | |
| 3966 | const sym = zo.symbol(zo.eh_frame_index orelse break :base_offset 0); | |
| 3967 | break :base_offset sym.atom(self).?.size; | |
| 3968 | } else 0; | |
| 3969 | const sh_offset = shdr.sh_offset + base_offset; | |
| 3970 | const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; | |
| 3971 | ||
| 3972 | const buffer = try gpa.alloc(u8, sh_size); | |
| 3973 | defer gpa.free(buffer); | |
| 3974 | const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and | |
| 3975 | shdr.sh_flags & elf.SHF_EXECINSTR != 0 and self.getTarget().cpu.arch == .x86_64) | |
| 3976 | 0xcc // int3 | |
| 3977 | else | |
| 3978 | 0; | |
| 3979 | @memset(buffer, padding_byte); | |
| 3980 | ||
| 3981 | for (atom_list.items) |ref| { | |
| 3982 | const atom_ptr = self.atom(ref).?; | |
| 3983 | assert(atom_ptr.alive); | |
| 3984 | ||
| 3985 | const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(base_offset))) orelse | |
| 3986 | return error.Overflow; | |
| 3987 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | |
| 3988 | ||
| 3989 | log.debug("writing atom({}) at 0x{x}", .{ ref, sh_offset + offset }); | |
| 3990 | ||
| 3991 | // TODO decompress directly into provided buffer | |
| 3992 | const out_code = buffer[offset..][0..size]; | |
| 3993 | const in_code = switch (atom_ptr.file(self).?) { | |
| 3994 | .object => |x| try x.codeDecompressAlloc(self, ref.index), | |
| 3995 | .zig_object => |x| try x.codeAlloc(self, ref.index), | |
| 3996 | else => unreachable, | |
| 3997 | }; | |
| 3998 | defer gpa.free(in_code); | |
| 3999 | @memcpy(out_code, in_code); | |
| 4000 | ||
| 4001 | const res = if (shdr.sh_flags & elf.SHF_ALLOC == 0) | |
| 4002 | atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs) | |
| 4003 | else | |
| 4004 | atom_ptr.resolveRelocsAlloc(self, out_code); | |
| 4005 | _ = res catch |err| switch (err) { | |
| 4006 | error.UnsupportedCpuArch => { | |
| 4007 | try self.reportUnsupportedCpuArch(); | |
| 4008 | return error.FlushFailure; | |
| 4009 | }, | |
| 4010 | error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, | |
| 4011 | else => |e| return e, | |
| 4012 | }; | |
| 4013 | } | |
| 4014 | ||
| 4015 | try self.base.file.?.pwriteAll(buffer, sh_offset); | |
| 4058 | if (atom_list.atoms.items.len == 0) continue; | |
| 4059 | atom_list.write(&buffer, &undefs, self) catch |err| switch (err) { | |
| 4060 | error.UnsupportedCpuArch => { | |
| 4061 | try self.reportUnsupportedCpuArch(); | |
| 4062 | return error.FlushFailure; | |
| 4063 | }, | |
| 4064 | error.RelocFailure, error.RelaxFailure => has_reloc_errors = true, | |
| 4065 | else => |e| return e, | |
| 4066 | }; | |
| 4016 | 4067 | } |
| 4017 | 4068 | |
| 4018 | if (self.requiresThunks()) { | |
| 4019 | var buffer = std.ArrayList(u8).init(gpa); | |
| 4020 | defer buffer.deinit(); | |
| 4069 | try self.reportUndefinedSymbols(&undefs); | |
| 4070 | if (has_reloc_errors) return error.FlushFailure; | |
| 4021 | 4071 | |
| 4072 | if (self.requiresThunks()) { | |
| 4022 | 4073 | for (self.thunks.items) |th| { |
| 4023 | 4074 | const thunk_size = th.size(self); |
| 4024 | 4075 | try buffer.ensureUnusedCapacity(thunk_size); |
| ... | ... | @@ -4030,10 +4081,6 @@ fn writeAtoms(self: *Elf) !void { |
| 4030 | 4081 | buffer.clearRetainingCapacity(); |
| 4031 | 4082 | } |
| 4032 | 4083 | } |
| 4033 | ||
| 4034 | try self.reportUndefinedSymbols(&undefs); | |
| 4035 | ||
| 4036 | if (has_reloc_errors) return error.FlushFailure; | |
| 4037 | 4084 | } |
| 4038 | 4085 | |
| 4039 | 4086 | pub fn updateSymtabSize(self: *Elf) !void { |
| ... | ... | @@ -4667,34 +4714,6 @@ pub fn isEffectivelyDynLib(self: Elf) bool { |
| 4667 | 4714 | }; |
| 4668 | 4715 | } |
| 4669 | 4716 | |
| 4670 | pub fn isZigSection(self: Elf, shndx: u32) bool { | |
| 4671 | inline for (&[_]?u32{ | |
| 4672 | self.zig_text_section_index, | |
| 4673 | self.zig_data_rel_ro_section_index, | |
| 4674 | self.zig_data_section_index, | |
| 4675 | self.zig_bss_section_index, | |
| 4676 | }) |index| { | |
| 4677 | if (index == shndx) return true; | |
| 4678 | } | |
| 4679 | return false; | |
| 4680 | } | |
| 4681 | ||
| 4682 | pub fn isDebugSection(self: Elf, shndx: u32) bool { | |
| 4683 | inline for (&[_]?u32{ | |
| 4684 | self.debug_info_section_index, | |
| 4685 | self.debug_abbrev_section_index, | |
| 4686 | self.debug_str_section_index, | |
| 4687 | self.debug_aranges_section_index, | |
| 4688 | self.debug_line_section_index, | |
| 4689 | self.debug_line_str_section_index, | |
| 4690 | self.debug_loclists_section_index, | |
| 4691 | self.debug_rnglists_section_index, | |
| 4692 | }) |index| { | |
| 4693 | if (index == shndx) return true; | |
| 4694 | } | |
| 4695 | return false; | |
| 4696 | } | |
| 4697 | ||
| 4698 | 4717 | pub fn addPhdr(self: *Elf, opts: struct { |
| 4699 | 4718 | type: u32 = 0, |
| 4700 | 4719 | flags: u32 = 0, |
| ... | ... | @@ -5070,7 +5089,7 @@ fn reportMissingLibraryError( |
| 5070 | 5089 | } |
| 5071 | 5090 | } |
| 5072 | 5091 | |
| 5073 | pub fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { | |
| 5092 | fn reportUnsupportedCpuArch(self: *Elf) error{OutOfMemory}!void { | |
| 5074 | 5093 | var err = try self.base.addErrorWithNotes(0); |
| 5075 | 5094 | try err.addMsg("fatal linker error: unsupported CPU architecture {s}", .{ |
| 5076 | 5095 | @tagName(self.getTarget().cpu.arch), |
| ... | ... | @@ -5282,6 +5301,14 @@ fn fmtDumpState( |
| 5282 | 5301 | try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); |
| 5283 | 5302 | } |
| 5284 | 5303 | |
| 5304 | const slice = self.sections.slice(); | |
| 5305 | { | |
| 5306 | try writer.writeAll("atom lists\n"); | |
| 5307 | for (slice.items(.shdr), slice.items(.atom_list_2), 0..) |shdr, atom_list, shndx| { | |
| 5308 | try writer.print("shdr({d}) : {s} : {}", .{ shndx, self.getShString(shdr.sh_name), atom_list.fmt(self) }); | |
| 5309 | } | |
| 5310 | } | |
| 5311 | ||
| 5285 | 5312 | if (self.requiresThunks()) { |
| 5286 | 5313 | try writer.writeAll("thunks\n"); |
| 5287 | 5314 | for (self.thunks.items, 0..) |th, index| { |
| ... | ... | @@ -5303,7 +5330,7 @@ fn fmtDumpState( |
| 5303 | 5330 | } |
| 5304 | 5331 | |
| 5305 | 5332 | try writer.writeAll("\nOutput shdrs\n"); |
| 5306 | for (self.sections.items(.shdr), self.sections.items(.phndx), 0..) |shdr, phndx, shndx| { | |
| 5333 | for (slice.items(.shdr), slice.items(.phndx), 0..) |shdr, phndx, shndx| { | |
| 5307 | 5334 | try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ |
| 5308 | 5335 | shndx, |
| 5309 | 5336 | phndx, |
| ... | ... | @@ -5373,7 +5400,6 @@ fn requiresThunks(self: Elf) bool { |
| 5373 | 5400 | /// so that we reserve enough space for the program header table up-front. |
| 5374 | 5401 | /// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding |
| 5375 | 5402 | /// more special-purpose program headers. |
| 5376 | pub const number_of_zig_segments = 4; | |
| 5377 | 5403 | const max_number_of_object_segments = 9; |
| 5378 | 5404 | const max_number_of_special_phdrs = 5; |
| 5379 | 5405 | |
| ... | ... | @@ -5558,8 +5584,14 @@ const Section = struct { |
| 5558 | 5584 | phndx: ?u32 = null, |
| 5559 | 5585 | |
| 5560 | 5586 | /// List of atoms contributing to this section. |
| 5587 | /// TODO currently this is only used for relocations tracking in relocatable mode | |
| 5588 | /// but will be merged with atom_list_2. | |
| 5561 | 5589 | atom_list: std.ArrayListUnmanaged(Ref) = .{}, |
| 5562 | 5590 | |
| 5591 | /// List of atoms contributing to this section. | |
| 5592 | /// This can be used by sections that require special handling such as init/fini array, etc. | |
| 5593 | atom_list_2: AtomList = .{}, | |
| 5594 | ||
| 5563 | 5595 | /// Index of the last allocated atom in this section. |
| 5564 | 5596 | last_atom: Ref = .{ .index = 0, .file = 0 }, |
| 5565 | 5597 | |
| ... | ... | @@ -5588,9 +5620,10 @@ fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 { |
| 5588 | 5620 | }; |
| 5589 | 5621 | } |
| 5590 | 5622 | |
| 5591 | fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { | |
| 5623 | fn createThunks(elf_file: *Elf, atom_list: *AtomList) !void { | |
| 5592 | 5624 | const gpa = elf_file.base.comp.gpa; |
| 5593 | 5625 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 5626 | ||
| 5594 | 5627 | // A branch will need an extender if its target is larger than |
| 5595 | 5628 | // `2^(jump_bits - 1) - margin` where margin is some arbitrary number. |
| 5596 | 5629 | const max_distance = switch (cpu_arch) { |
| ... | ... | @@ -5598,36 +5631,44 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { |
| 5598 | 5631 | .x86_64, .riscv64 => unreachable, |
| 5599 | 5632 | else => @panic("unhandled arch"), |
| 5600 | 5633 | }; |
| 5601 | const atoms = elf_file.sections.items(.atom_list)[shndx].items; | |
| 5602 | assert(atoms.len > 0); | |
| 5603 | 5634 | |
| 5604 | for (atoms) |ref| { | |
| 5635 | const advance = struct { | |
| 5636 | fn advance(list: *AtomList, size: u64, alignment: Atom.Alignment) !i64 { | |
| 5637 | const offset = alignment.forward(list.size); | |
| 5638 | const padding = offset - list.size; | |
| 5639 | list.size += padding + size; | |
| 5640 | list.alignment = list.alignment.max(alignment); | |
| 5641 | return @intCast(offset); | |
| 5642 | } | |
| 5643 | }.advance; | |
| 5644 | ||
| 5645 | for (atom_list.atoms.items) |ref| { | |
| 5605 | 5646 | elf_file.atom(ref).?.value = -1; |
| 5606 | 5647 | } |
| 5607 | 5648 | |
| 5608 | 5649 | var i: usize = 0; |
| 5609 | while (i < atoms.len) { | |
| 5650 | while (i < atom_list.atoms.items.len) { | |
| 5610 | 5651 | const start = i; |
| 5611 | const start_atom = elf_file.atom(atoms[start]).?; | |
| 5652 | const start_atom = elf_file.atom(atom_list.atoms.items[start]).?; | |
| 5612 | 5653 | assert(start_atom.alive); |
| 5613 | start_atom.value = try advanceSection(shdr, start_atom.size, start_atom.alignment); | |
| 5654 | start_atom.value = try advance(atom_list, start_atom.size, start_atom.alignment); | |
| 5614 | 5655 | i += 1; |
| 5615 | 5656 | |
| 5616 | while (i < atoms.len) : (i += 1) { | |
| 5617 | const atom_ptr = elf_file.atom(atoms[i]).?; | |
| 5657 | while (i < atom_list.atoms.items.len) : (i += 1) { | |
| 5658 | const atom_ptr = elf_file.atom(atom_list.atoms.items[i]).?; | |
| 5618 | 5659 | assert(atom_ptr.alive); |
| 5619 | if (@as(i64, @intCast(atom_ptr.alignment.forward(shdr.sh_size))) - start_atom.value >= max_distance) | |
| 5660 | if (@as(i64, @intCast(atom_ptr.alignment.forward(atom_list.size))) - start_atom.value >= max_distance) | |
| 5620 | 5661 | break; |
| 5621 | atom_ptr.value = try advanceSection(shdr, atom_ptr.size, atom_ptr.alignment); | |
| 5662 | atom_ptr.value = try advance(atom_list, atom_ptr.size, atom_ptr.alignment); | |
| 5622 | 5663 | } |
| 5623 | 5664 | |
| 5624 | 5665 | // Insert a thunk at the group end |
| 5625 | 5666 | const thunk_index = try elf_file.addThunk(); |
| 5626 | 5667 | const thunk_ptr = elf_file.thunk(thunk_index); |
| 5627 | thunk_ptr.output_section_index = shndx; | |
| 5668 | thunk_ptr.output_section_index = atom_list.output_section_index; | |
| 5628 | 5669 | |
| 5629 | 5670 | // Scan relocs in the group and create trampolines for any unreachable callsite |
| 5630 | for (atoms[start..i]) |ref| { | |
| 5671 | for (atom_list.atoms.items[start..i]) |ref| { | |
| 5631 | 5672 | const atom_ptr = elf_file.atom(ref).?; |
| 5632 | 5673 | const file_ptr = atom_ptr.file(elf_file).?; |
| 5633 | 5674 | log.debug("atom({}) {s}", .{ ref, atom_ptr.name(elf_file) }); |
| ... | ... | @@ -5657,18 +5698,11 @@ fn createThunks(elf_file: *Elf, shdr: *elf.Elf64_Shdr, shndx: u32) !void { |
| 5657 | 5698 | atom_ptr.addExtra(.{ .thunk = thunk_index }, elf_file); |
| 5658 | 5699 | } |
| 5659 | 5700 | |
| 5660 | thunk_ptr.value = try advanceSection(shdr, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); | |
| 5701 | thunk_ptr.value = try advance(atom_list, thunk_ptr.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2)); | |
| 5661 | 5702 | |
| 5662 | 5703 | log.debug("thunk({d}) : {}", .{ thunk_index, thunk_ptr.fmt(elf_file) }); |
| 5663 | 5704 | } |
| 5664 | 5705 | } |
| 5665 | fn advanceSection(shdr: *elf.Elf64_Shdr, adv_size: u64, alignment: Atom.Alignment) !i64 { | |
| 5666 | const offset = alignment.forward(shdr.sh_size); | |
| 5667 | const padding = offset - shdr.sh_size; | |
| 5668 | shdr.sh_size += padding + adv_size; | |
| 5669 | shdr.sh_addralign = @max(shdr.sh_addralign, alignment.toByteUnits() orelse 1); | |
| 5670 | return @intCast(offset); | |
| 5671 | } | |
| 5672 | 5706 | |
| 5673 | 5707 | const std = @import("std"); |
| 5674 | 5708 | const build_options = @import("build_options"); |
| ... | ... | @@ -5699,6 +5733,7 @@ const Air = @import("../Air.zig"); |
| 5699 | 5733 | const Allocator = std.mem.Allocator; |
| 5700 | 5734 | const Archive = @import("Elf/Archive.zig"); |
| 5701 | 5735 | pub const Atom = @import("Elf/Atom.zig"); |
| 5736 | const AtomList = @import("Elf/AtomList.zig"); | |
| 5702 | 5737 | const Cache = std.Build.Cache; |
| 5703 | 5738 | const Path = Cache.Path; |
| 5704 | 5739 | const Compilation = @import("../Compilation.zig"); |
src/link/Elf/Atom.zig+15-144| ... | ... | @@ -51,6 +51,11 @@ pub fn address(self: Atom, elf_file: *Elf) i64 { |
| 51 | 51 | return @as(i64, @intCast(shdr.sh_addr)) + self.value; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | pub fn offset(self: Atom, elf_file: *Elf) u64 { | |
| 55 | const shdr = elf_file.sections.items(.shdr)[self.output_section_index]; | |
| 56 | return shdr.sh_offset + @as(u64, @intCast(self.value)); | |
| 57 | } | |
| 58 | ||
| 54 | 59 | pub fn ref(self: Atom) Elf.Ref { |
| 55 | 60 | return .{ .index = self.atom_index, .file = self.file_index }; |
| 56 | 61 | } |
| ... | ... | @@ -123,140 +128,6 @@ pub fn freeListEligible(self: Atom, elf_file: *Elf) bool { |
| 123 | 128 | return surplus >= Elf.min_text_capacity; |
| 124 | 129 | } |
| 125 | 130 | |
| 126 | pub fn allocate(self: *Atom, elf_file: *Elf) !void { | |
| 127 | const slice = elf_file.sections.slice(); | |
| 128 | const shdr = &slice.items(.shdr)[self.output_section_index]; | |
| 129 | const free_list = &slice.items(.free_list)[self.output_section_index]; | |
| 130 | const last_atom_ref = &slice.items(.last_atom)[self.output_section_index]; | |
| 131 | const new_atom_ideal_capacity = Elf.padToIdeal(self.size); | |
| 132 | ||
| 133 | // We use these to indicate our intention to update metadata, placing the new atom, | |
| 134 | // and possibly removing a free list node. | |
| 135 | // It would be simpler to do it inside the for loop below, but that would cause a | |
| 136 | // problem if an error was returned later in the function. So this action | |
| 137 | // is actually carried out at the end of the function, when errors are no longer possible. | |
| 138 | var atom_placement: ?Elf.Ref = null; | |
| 139 | var free_list_removal: ?usize = null; | |
| 140 | ||
| 141 | // First we look for an appropriately sized free list node. | |
| 142 | // The list is unordered. We'll just take the first thing that works. | |
| 143 | self.value = blk: { | |
| 144 | var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len; | |
| 145 | while (i < free_list.items.len) { | |
| 146 | const big_atom_ref = free_list.items[i]; | |
| 147 | const big_atom = elf_file.atom(big_atom_ref).?; | |
| 148 | // We now have a pointer to a live atom that has too much capacity. | |
| 149 | // Is it enough that we could fit this new atom? | |
| 150 | const cap = big_atom.capacity(elf_file); | |
| 151 | const ideal_capacity = Elf.padToIdeal(cap); | |
| 152 | const ideal_capacity_end_vaddr = std.math.add(u64, @intCast(big_atom.value), ideal_capacity) catch ideal_capacity; | |
| 153 | const capacity_end_vaddr = @as(u64, @intCast(big_atom.value)) + cap; | |
| 154 | const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity; | |
| 155 | const new_start_vaddr = self.alignment.backward(new_start_vaddr_unaligned); | |
| 156 | if (new_start_vaddr < ideal_capacity_end_vaddr) { | |
| 157 | // Additional bookkeeping here to notice if this free list node | |
| 158 | // should be deleted because the block that it points to has grown to take up | |
| 159 | // more of the extra capacity. | |
| 160 | if (!big_atom.freeListEligible(elf_file)) { | |
| 161 | _ = free_list.swapRemove(i); | |
| 162 | } else { | |
| 163 | i += 1; | |
| 164 | } | |
| 165 | continue; | |
| 166 | } | |
| 167 | // At this point we know that we will place the new block here. But the | |
| 168 | // remaining question is whether there is still yet enough capacity left | |
| 169 | // over for there to still be a free list node. | |
| 170 | const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr; | |
| 171 | const keep_free_list_node = remaining_capacity >= Elf.min_text_capacity; | |
| 172 | ||
| 173 | // Set up the metadata to be updated, after errors are no longer possible. | |
| 174 | atom_placement = big_atom_ref; | |
| 175 | if (!keep_free_list_node) { | |
| 176 | free_list_removal = i; | |
| 177 | } | |
| 178 | break :blk @intCast(new_start_vaddr); | |
| 179 | } else if (elf_file.atom(last_atom_ref.*)) |last_atom| { | |
| 180 | const ideal_capacity = Elf.padToIdeal(last_atom.size); | |
| 181 | const ideal_capacity_end_vaddr = @as(u64, @intCast(last_atom.value)) + ideal_capacity; | |
| 182 | const new_start_vaddr = self.alignment.forward(ideal_capacity_end_vaddr); | |
| 183 | // Set up the metadata to be updated, after errors are no longer possible. | |
| 184 | atom_placement = last_atom.ref(); | |
| 185 | break :blk @intCast(new_start_vaddr); | |
| 186 | } else { | |
| 187 | break :blk 0; | |
| 188 | } | |
| 189 | }; | |
| 190 | ||
| 191 | log.debug("allocated atom({}) : '{s}' at 0x{x} to 0x{x}", .{ | |
| 192 | self.ref(), | |
| 193 | self.name(elf_file), | |
| 194 | self.address(elf_file), | |
| 195 | self.address(elf_file) + @as(i64, @intCast(self.size)), | |
| 196 | }); | |
| 197 | ||
| 198 | const expand_section = if (atom_placement) |placement_ref| | |
| 199 | elf_file.atom(placement_ref).?.nextAtom(elf_file) == null | |
| 200 | else | |
| 201 | true; | |
| 202 | if (expand_section) { | |
| 203 | const needed_size: u64 = @intCast(self.value + @as(i64, @intCast(self.size))); | |
| 204 | try elf_file.growAllocSection(self.output_section_index, needed_size); | |
| 205 | last_atom_ref.* = self.ref(); | |
| 206 | ||
| 207 | switch (self.file(elf_file).?) { | |
| 208 | .zig_object => |zo| if (zo.dwarf) |_| { | |
| 209 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address | |
| 210 | // range of the compilation unit. When we expand the text section, this range changes, | |
| 211 | // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. | |
| 212 | zo.debug_info_section_dirty = true; | |
| 213 | // This becomes dirty for the same reason. We could potentially make this more | |
| 214 | // fine-grained with the addition of support for more compilation units. It is planned to | |
| 215 | // model each package as a different compilation unit. | |
| 216 | zo.debug_aranges_section_dirty = true; | |
| 217 | zo.debug_rnglists_section_dirty = true; | |
| 218 | }, | |
| 219 | else => {}, | |
| 220 | } | |
| 221 | } | |
| 222 | shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnits().?); | |
| 223 | ||
| 224 | // This function can also reallocate an atom. | |
| 225 | // In this case we need to "unplug" it from its previous location before | |
| 226 | // plugging it in to its new location. | |
| 227 | if (self.prevAtom(elf_file)) |prev| { | |
| 228 | prev.next_atom_ref = self.next_atom_ref; | |
| 229 | } | |
| 230 | if (self.nextAtom(elf_file)) |next| { | |
| 231 | next.prev_atom_ref = self.prev_atom_ref; | |
| 232 | } | |
| 233 | ||
| 234 | if (atom_placement) |big_atom_ref| { | |
| 235 | const big_atom = elf_file.atom(big_atom_ref).?; | |
| 236 | self.prev_atom_ref = big_atom_ref; | |
| 237 | self.next_atom_ref = big_atom.next_atom_ref; | |
| 238 | big_atom.next_atom_ref = self.ref(); | |
| 239 | } else { | |
| 240 | self.prev_atom_ref = .{ .index = 0, .file = 0 }; | |
| 241 | self.next_atom_ref = .{ .index = 0, .file = 0 }; | |
| 242 | } | |
| 243 | if (free_list_removal) |i| { | |
| 244 | _ = free_list.swapRemove(i); | |
| 245 | } | |
| 246 | ||
| 247 | self.alive = true; | |
| 248 | } | |
| 249 | ||
| 250 | pub fn shrink(self: *Atom, elf_file: *Elf) void { | |
| 251 | _ = self; | |
| 252 | _ = elf_file; | |
| 253 | } | |
| 254 | ||
| 255 | pub fn grow(self: *Atom, elf_file: *Elf) !void { | |
| 256 | if (!self.alignment.check(@intCast(self.value)) or self.size > self.capacity(elf_file)) | |
| 257 | try self.allocate(elf_file); | |
| 258 | } | |
| 259 | ||
| 260 | 131 | pub fn free(self: *Atom, elf_file: *Elf) void { |
| 261 | 132 | log.debug("freeAtom atom({}) ({s})", .{ self.ref(), self.name(elf_file) }); |
| 262 | 133 | |
| ... | ... | @@ -1807,7 +1678,7 @@ const aarch64 = struct { |
| 1807 | 1678 | => { |
| 1808 | 1679 | // TODO: NC means no overflow check |
| 1809 | 1680 | const taddr = @as(u64, @intCast(S + A)); |
| 1810 | const offset: u12 = switch (r_type) { | |
| 1681 | const off: u12 = switch (r_type) { | |
| 1811 | 1682 | .LDST8_ABS_LO12_NC => @truncate(taddr), |
| 1812 | 1683 | .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2), |
| 1813 | 1684 | .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4), |
| ... | ... | @@ -1815,7 +1686,7 @@ const aarch64 = struct { |
| 1815 | 1686 | .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), |
| 1816 | 1687 | else => unreachable, |
| 1817 | 1688 | }; |
| 1818 | aarch64_util.writeLoadStoreRegInst(offset, code); | |
| 1689 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1819 | 1690 | }, |
| 1820 | 1691 | |
| 1821 | 1692 | .TLSLE_ADD_TPREL_HI12 => { |
| ... | ... | @@ -1839,8 +1710,8 @@ const aarch64 = struct { |
| 1839 | 1710 | .TLSIE_LD64_GOTTPREL_LO12_NC => { |
| 1840 | 1711 | const S_ = target.gotTpAddress(elf_file); |
| 1841 | 1712 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1842 | const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); | |
| 1843 | aarch64_util.writeLoadStoreRegInst(offset, code); | |
| 1713 | const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); | |
| 1714 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1844 | 1715 | }, |
| 1845 | 1716 | |
| 1846 | 1717 | .TLSGD_ADR_PAGE21 => { |
| ... | ... | @@ -1853,8 +1724,8 @@ const aarch64 = struct { |
| 1853 | 1724 | .TLSGD_ADD_LO12_NC => { |
| 1854 | 1725 | const S_ = target.tlsGdAddress(elf_file); |
| 1855 | 1726 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1856 | const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); | |
| 1857 | aarch64_util.writeAddImmInst(offset, code); | |
| 1727 | const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); | |
| 1728 | aarch64_util.writeAddImmInst(off, code); | |
| 1858 | 1729 | }, |
| 1859 | 1730 | |
| 1860 | 1731 | .TLSDESC_ADR_PAGE21 => { |
| ... | ... | @@ -1873,8 +1744,8 @@ const aarch64 = struct { |
| 1873 | 1744 | if (target.flags.has_tlsdesc) { |
| 1874 | 1745 | const S_ = target.tlsDescAddress(elf_file); |
| 1875 | 1746 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1876 | const offset: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); | |
| 1877 | aarch64_util.writeLoadStoreRegInst(offset, code); | |
| 1747 | const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); | |
| 1748 | aarch64_util.writeLoadStoreRegInst(off, code); | |
| 1878 | 1749 | } else { |
| 1879 | 1750 | relocs_log.debug(" relaxing ldr => nop", .{}); |
| 1880 | 1751 | mem.writeInt(u32, code, Instruction.nop().toU32(), .little); |
| ... | ... | @@ -1885,8 +1756,8 @@ const aarch64 = struct { |
| 1885 | 1756 | if (target.flags.has_tlsdesc) { |
| 1886 | 1757 | const S_ = target.tlsDescAddress(elf_file); |
| 1887 | 1758 | relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); |
| 1888 | const offset: u12 = @truncate(@as(u64, @bitCast(S_ + A))); | |
| 1889 | aarch64_util.writeAddImmInst(offset, code); | |
| 1759 | const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); | |
| 1760 | aarch64_util.writeAddImmInst(off, code); | |
| 1890 | 1761 | } else { |
| 1891 | 1762 | const old_inst = Instruction{ |
| 1892 | 1763 | .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( |
src/link/Elf/AtomList.zig created+208| ... | ... | @@ -0,0 +1,208 @@ |
| 1 | value: i64 = 0, | |
| 2 | size: u64 = 0, | |
| 3 | alignment: Atom.Alignment = .@"1", | |
| 4 | output_section_index: u32 = 0, | |
| 5 | atoms: std.ArrayListUnmanaged(Elf.Ref) = .{}, | |
| 6 | ||
| 7 | pub fn deinit(list: *AtomList, allocator: Allocator) void { | |
| 8 | list.atoms.deinit(allocator); | |
| 9 | } | |
| 10 | ||
| 11 | pub fn address(list: AtomList, elf_file: *Elf) i64 { | |
| 12 | const shdr = elf_file.sections.items(.shdr)[list.output_section_index]; | |
| 13 | return @as(i64, @intCast(shdr.sh_addr)) + list.value; | |
| 14 | } | |
| 15 | ||
| 16 | pub fn offset(list: AtomList, elf_file: *Elf) u64 { | |
| 17 | const shdr = elf_file.sections.items(.shdr)[list.output_section_index]; | |
| 18 | return shdr.sh_offset + @as(u64, @intCast(list.value)); | |
| 19 | } | |
| 20 | ||
| 21 | pub fn updateSize(list: *AtomList, elf_file: *Elf) void { | |
| 22 | for (list.atoms.items) |ref| { | |
| 23 | const atom_ptr = elf_file.atom(ref).?; | |
| 24 | assert(atom_ptr.alive); | |
| 25 | const off = atom_ptr.alignment.forward(list.size); | |
| 26 | const padding = off - list.size; | |
| 27 | atom_ptr.value = @intCast(off); | |
| 28 | list.size += padding + atom_ptr.size; | |
| 29 | list.alignment = list.alignment.max(atom_ptr.alignment); | |
| 30 | } | |
| 31 | } | |
| 32 | ||
| 33 | pub fn allocate(list: *AtomList, elf_file: *Elf) !void { | |
| 34 | const alloc_res = try elf_file.allocateChunk(.{ | |
| 35 | .shndx = list.output_section_index, | |
| 36 | .size = list.size, | |
| 37 | .alignment = list.alignment, | |
| 38 | .requires_padding = false, | |
| 39 | }); | |
| 40 | list.value = @intCast(alloc_res.value); | |
| 41 | ||
| 42 | const slice = elf_file.sections.slice(); | |
| 43 | const shdr = &slice.items(.shdr)[list.output_section_index]; | |
| 44 | const last_atom_ref = &slice.items(.last_atom)[list.output_section_index]; | |
| 45 | ||
| 46 | const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom| | |
| 47 | placement_atom.nextAtom(elf_file) == null | |
| 48 | else | |
| 49 | true; | |
| 50 | if (expand_section) last_atom_ref.* = list.lastAtom(elf_file).ref(); | |
| 51 | shdr.sh_addralign = @max(shdr.sh_addralign, list.alignment.toByteUnits().?); | |
| 52 | ||
| 53 | // FIXME:JK this currently ignores Thunks as valid chunks. | |
| 54 | { | |
| 55 | var idx: usize = 0; | |
| 56 | while (idx < list.atoms.items.len) : (idx += 1) { | |
| 57 | const curr_atom_ptr = elf_file.atom(list.atoms.items[idx]).?; | |
| 58 | if (idx > 0) { | |
| 59 | curr_atom_ptr.prev_atom_ref = list.atoms.items[idx - 1]; | |
| 60 | } | |
| 61 | if (idx + 1 < list.atoms.items.len) { | |
| 62 | curr_atom_ptr.next_atom_ref = list.atoms.items[idx + 1]; | |
| 63 | } | |
| 64 | } | |
| 65 | } | |
| 66 | ||
| 67 | if (elf_file.atom(alloc_res.placement)) |placement_atom| { | |
| 68 | list.firstAtom(elf_file).prev_atom_ref = placement_atom.ref(); | |
| 69 | list.lastAtom(elf_file).next_atom_ref = placement_atom.next_atom_ref; | |
| 70 | placement_atom.next_atom_ref = list.firstAtom(elf_file).ref(); | |
| 71 | } | |
| 72 | ||
| 73 | // FIXME:JK if we had a link from Atom to parent AtomList we would not need to update Atom's value or osec index | |
| 74 | for (list.atoms.items) |ref| { | |
| 75 | const atom_ptr = elf_file.atom(ref).?; | |
| 76 | atom_ptr.output_section_index = list.output_section_index; | |
| 77 | atom_ptr.value += list.value; | |
| 78 | } | |
| 79 | } | |
| 80 | ||
| 81 | pub fn write(list: AtomList, buffer: *std.ArrayList(u8), undefs: anytype, elf_file: *Elf) !void { | |
| 82 | const gpa = elf_file.base.comp.gpa; | |
| 83 | const osec = elf_file.sections.items(.shdr)[list.output_section_index]; | |
| 84 | assert(osec.sh_type != elf.SHT_NOBITS); | |
| 85 | ||
| 86 | log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); | |
| 87 | ||
| 88 | const list_size = math.cast(usize, list.size) orelse return error.Overflow; | |
| 89 | try buffer.ensureUnusedCapacity(list_size); | |
| 90 | buffer.appendNTimesAssumeCapacity(0, list_size); | |
| 91 | ||
| 92 | for (list.atoms.items) |ref| { | |
| 93 | const atom_ptr = elf_file.atom(ref).?; | |
| 94 | assert(atom_ptr.alive); | |
| 95 | ||
| 96 | const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow; | |
| 97 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | |
| 98 | ||
| 99 | log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); | |
| 100 | ||
| 101 | const object = atom_ptr.file(elf_file).?.object; | |
| 102 | const code = try object.codeDecompressAlloc(elf_file, ref.index); | |
| 103 | defer gpa.free(code); | |
| 104 | const out_code = buffer.items[off..][0..size]; | |
| 105 | @memcpy(out_code, code); | |
| 106 | ||
| 107 | if (osec.sh_flags & elf.SHF_ALLOC == 0) | |
| 108 | try atom_ptr.resolveRelocsNonAlloc(elf_file, out_code, undefs) | |
| 109 | else | |
| 110 | try atom_ptr.resolveRelocsAlloc(elf_file, out_code); | |
| 111 | } | |
| 112 | ||
| 113 | try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file)); | |
| 114 | buffer.clearRetainingCapacity(); | |
| 115 | } | |
| 116 | ||
| 117 | pub fn writeRelocatable(list: AtomList, buffer: *std.ArrayList(u8), elf_file: *Elf) !void { | |
| 118 | const gpa = elf_file.base.comp.gpa; | |
| 119 | const osec = elf_file.sections.items(.shdr)[list.output_section_index]; | |
| 120 | assert(osec.sh_type != elf.SHT_NOBITS); | |
| 121 | ||
| 122 | log.debug("writing atoms in section '{s}'", .{elf_file.getShString(osec.sh_name)}); | |
| 123 | ||
| 124 | const list_size = math.cast(usize, list.size) orelse return error.Overflow; | |
| 125 | try buffer.ensureUnusedCapacity(list_size); | |
| 126 | buffer.appendNTimesAssumeCapacity(0, list_size); | |
| 127 | ||
| 128 | for (list.atoms.items) |ref| { | |
| 129 | const atom_ptr = elf_file.atom(ref).?; | |
| 130 | assert(atom_ptr.alive); | |
| 131 | ||
| 132 | const off = math.cast(usize, atom_ptr.value - list.value) orelse return error.Overflow; | |
| 133 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | |
| 134 | ||
| 135 | log.debug(" atom({}) at 0x{x}", .{ ref, list.offset(elf_file) + off }); | |
| 136 | ||
| 137 | const object = atom_ptr.file(elf_file).?.object; | |
| 138 | const code = try object.codeDecompressAlloc(elf_file, ref.index); | |
| 139 | defer gpa.free(code); | |
| 140 | const out_code = buffer.items[off..][0..size]; | |
| 141 | @memcpy(out_code, code); | |
| 142 | } | |
| 143 | ||
| 144 | try elf_file.base.file.?.pwriteAll(buffer.items, list.offset(elf_file)); | |
| 145 | buffer.clearRetainingCapacity(); | |
| 146 | } | |
| 147 | ||
| 148 | pub fn firstAtom(list: AtomList, elf_file: *Elf) *Atom { | |
| 149 | assert(list.atoms.items.len > 0); | |
| 150 | return elf_file.atom(list.atoms.items[0]).?; | |
| 151 | } | |
| 152 | ||
| 153 | pub fn lastAtom(list: AtomList, elf_file: *Elf) *Atom { | |
| 154 | assert(list.atoms.items.len > 0); | |
| 155 | return elf_file.atom(list.atoms.items[list.atoms.items.len - 1]).?; | |
| 156 | } | |
| 157 | ||
| 158 | pub fn format( | |
| 159 | list: AtomList, | |
| 160 | comptime unused_fmt_string: []const u8, | |
| 161 | options: std.fmt.FormatOptions, | |
| 162 | writer: anytype, | |
| 163 | ) !void { | |
| 164 | _ = list; | |
| 165 | _ = unused_fmt_string; | |
| 166 | _ = options; | |
| 167 | _ = writer; | |
| 168 | @compileError("do not format AtomList directly"); | |
| 169 | } | |
| 170 | ||
| 171 | const FormatCtx = struct { AtomList, *Elf }; | |
| 172 | ||
| 173 | pub fn fmt(list: AtomList, elf_file: *Elf) std.fmt.Formatter(format2) { | |
| 174 | return .{ .data = .{ list, elf_file } }; | |
| 175 | } | |
| 176 | ||
| 177 | fn format2( | |
| 178 | ctx: FormatCtx, | |
| 179 | comptime unused_fmt_string: []const u8, | |
| 180 | options: std.fmt.FormatOptions, | |
| 181 | writer: anytype, | |
| 182 | ) !void { | |
| 183 | _ = unused_fmt_string; | |
| 184 | _ = options; | |
| 185 | const list, const elf_file = ctx; | |
| 186 | try writer.print("list : @{x} : shdr({d}) : align({x}) : size({x})", .{ | |
| 187 | list.address(elf_file), list.output_section_index, | |
| 188 | list.alignment.toByteUnits() orelse 0, list.size, | |
| 189 | }); | |
| 190 | try writer.writeAll(" : atoms{ "); | |
| 191 | for (list.atoms.items, 0..) |ref, i| { | |
| 192 | try writer.print("{}", .{ref}); | |
| 193 | if (i < list.atoms.items.len - 1) try writer.writeAll(", "); | |
| 194 | } | |
| 195 | try writer.writeAll(" }"); | |
| 196 | } | |
| 197 | ||
| 198 | const assert = std.debug.assert; | |
| 199 | const elf = std.elf; | |
| 200 | const log = std.log.scoped(.link); | |
| 201 | const math = std.math; | |
| 202 | const std = @import("std"); | |
| 203 | ||
| 204 | const Allocator = std.mem.Allocator; | |
| 205 | const Atom = @import("Atom.zig"); | |
| 206 | const AtomList = @This(); | |
| 207 | const Elf = @import("../Elf.zig"); | |
| 208 | const Object = @import("Object.zig"); |
src/link/Elf/Object.zig+42-81| ... | ... | @@ -311,58 +311,6 @@ fn initAtoms(self: *Object, allocator: Allocator, handle: std.fs.File, elf_file: |
| 311 | 311 | }; |
| 312 | 312 | } |
| 313 | 313 | |
| 314 | fn initOutputSection(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u32 { | |
| 315 | const name = blk: { | |
| 316 | const name = self.getString(shdr.sh_name); | |
| 317 | if (elf_file.base.isRelocatable()) break :blk name; | |
| 318 | if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name; | |
| 319 | const sh_name_prefixes: []const [:0]const u8 = &.{ | |
| 320 | ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss", | |
| 321 | ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors", | |
| 322 | ".dtors", ".gnu.warning", | |
| 323 | }; | |
| 324 | inline for (sh_name_prefixes) |prefix| { | |
| 325 | if (std.mem.eql(u8, name, prefix) or std.mem.startsWith(u8, name, prefix ++ ".")) { | |
| 326 | break :blk prefix; | |
| 327 | } | |
| 328 | } | |
| 329 | break :blk name; | |
| 330 | }; | |
| 331 | const @"type" = tt: { | |
| 332 | if (elf_file.getTarget().cpu.arch == .x86_64 and | |
| 333 | shdr.sh_type == elf.SHT_X86_64_UNWIND) break :tt elf.SHT_PROGBITS; | |
| 334 | ||
| 335 | const @"type" = switch (shdr.sh_type) { | |
| 336 | elf.SHT_NULL => unreachable, | |
| 337 | elf.SHT_PROGBITS => blk: { | |
| 338 | if (std.mem.eql(u8, name, ".init_array") or std.mem.startsWith(u8, name, ".init_array.")) | |
| 339 | break :blk elf.SHT_INIT_ARRAY; | |
| 340 | if (std.mem.eql(u8, name, ".fini_array") or std.mem.startsWith(u8, name, ".fini_array.")) | |
| 341 | break :blk elf.SHT_FINI_ARRAY; | |
| 342 | break :blk shdr.sh_type; | |
| 343 | }, | |
| 344 | else => shdr.sh_type, | |
| 345 | }; | |
| 346 | break :tt @"type"; | |
| 347 | }; | |
| 348 | const flags = blk: { | |
| 349 | var flags = shdr.sh_flags; | |
| 350 | if (!elf_file.base.isRelocatable()) { | |
| 351 | flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN); | |
| 352 | } | |
| 353 | break :blk switch (@"type") { | |
| 354 | elf.SHT_INIT_ARRAY, elf.SHT_FINI_ARRAY => flags | elf.SHF_WRITE, | |
| 355 | else => flags, | |
| 356 | }; | |
| 357 | }; | |
| 358 | const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{ | |
| 359 | .type = @"type", | |
| 360 | .flags = flags, | |
| 361 | .name = try elf_file.insertShString(name), | |
| 362 | }); | |
| 363 | return out_shndx; | |
| 364 | } | |
| 365 | ||
| 366 | 314 | fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool { |
| 367 | 315 | const comp = elf_file.base.comp; |
| 368 | 316 | const shdr = self.shdrs.items[index]; |
| ... | ... | @@ -438,15 +386,24 @@ fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: |
| 438 | 386 | .input_section_index = shndx, |
| 439 | 387 | .file_index = self.index, |
| 440 | 388 | }), |
| 441 | .fde => try self.fdes.append(allocator, .{ | |
| 442 | .offset = data_start + rec.offset, | |
| 443 | .size = rec.size, | |
| 444 | .cie_index = undefined, | |
| 445 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), | |
| 446 | .rel_num = @as(u32, @intCast(rel_range.len)), | |
| 447 | .input_section_index = shndx, | |
| 448 | .file_index = self.index, | |
| 449 | }), | |
| 389 | .fde => { | |
| 390 | if (rel_range.len == 0) { | |
| 391 | // No relocs for an FDE means we cannot associate this FDE to an Atom | |
| 392 | // so we skip it. According to mold source code | |
| 393 | // (https://github.com/rui314/mold/blob/a3e69502b0eaf1126d6093e8ea5e6fdb95219811/src/input-files.cc#L525-L528) | |
| 394 | // this can happen for object files built with -r flag by the linker. | |
| 395 | continue; | |
| 396 | } | |
| 397 | try self.fdes.append(allocator, .{ | |
| 398 | .offset = data_start + rec.offset, | |
| 399 | .size = rec.size, | |
| 400 | .cie_index = undefined, | |
| 401 | .rel_index = rel_start + @as(u32, @intCast(rel_range.start)), | |
| 402 | .rel_num = @as(u32, @intCast(rel_range.len)), | |
| 403 | .input_section_index = shndx, | |
| 404 | .file_index = self.index, | |
| 405 | }); | |
| 406 | }, | |
| 450 | 407 | } |
| 451 | 408 | } |
| 452 | 409 | |
| ... | ... | @@ -622,7 +579,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void { |
| 622 | 579 | } |
| 623 | 580 | } |
| 624 | 581 | |
| 625 | pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void { | |
| 582 | pub fn claimUnresolvedRelocatable(self: *Object, elf_file: *Elf) void { | |
| 626 | 583 | const first_global = self.first_global orelse return; |
| 627 | 584 | for (self.globals(), 0..) |*sym, i| { |
| 628 | 585 | const esym_index = @as(u32, @intCast(first_global + i)); |
| ... | ... | @@ -985,21 +942,14 @@ pub fn initOutputSections(self: *Object, elf_file: *Elf) !void { |
| 985 | 942 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 986 | 943 | if (!atom_ptr.alive) continue; |
| 987 | 944 | const shdr = atom_ptr.inputShdr(elf_file); |
| 988 | _ = try self.initOutputSection(elf_file, shdr); | |
| 989 | } | |
| 990 | } | |
| 991 | ||
| 992 | pub fn addAtomsToOutputSections(self: *Object, elf_file: *Elf) !void { | |
| 993 | for (self.atoms_indexes.items) |atom_index| { | |
| 994 | const atom_ptr = self.atom(atom_index) orelse continue; | |
| 995 | if (!atom_ptr.alive) continue; | |
| 996 | const shdr = atom_ptr.inputShdr(elf_file); | |
| 997 | atom_ptr.output_section_index = self.initOutputSection(elf_file, shdr) catch unreachable; | |
| 998 | ||
| 999 | const comp = elf_file.base.comp; | |
| 1000 | const gpa = comp.gpa; | |
| 1001 | const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index]; | |
| 1002 | try atom_list.append(gpa, .{ .index = atom_index, .file = self.index }); | |
| 945 | const osec = try elf_file.initOutputSection(.{ | |
| 946 | .name = self.getString(shdr.sh_name), | |
| 947 | .flags = shdr.sh_flags, | |
| 948 | .type = shdr.sh_type, | |
| 949 | }); | |
| 950 | const atom_list = &elf_file.sections.items(.atom_list_2)[osec]; | |
| 951 | atom_list.output_section_index = osec; | |
| 952 | try atom_list.atoms.append(elf_file.base.comp.gpa, atom_ptr.ref()); | |
| 1003 | 953 | } |
| 1004 | 954 | } |
| 1005 | 955 | |
| ... | ... | @@ -1007,9 +957,14 @@ pub fn initRelaSections(self: *Object, elf_file: *Elf) !void { |
| 1007 | 957 | for (self.atoms_indexes.items) |atom_index| { |
| 1008 | 958 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1009 | 959 | if (!atom_ptr.alive) continue; |
| 960 | if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; | |
| 1010 | 961 | const shndx = atom_ptr.relocsShndx() orelse continue; |
| 1011 | 962 | const shdr = self.shdrs.items[shndx]; |
| 1012 | const out_shndx = try self.initOutputSection(elf_file, shdr); | |
| 963 | const out_shndx = try elf_file.initOutputSection(.{ | |
| 964 | .name = self.getString(shdr.sh_name), | |
| 965 | .flags = shdr.sh_flags, | |
| 966 | .type = shdr.sh_type, | |
| 967 | }); | |
| 1013 | 968 | const out_shdr = &elf_file.sections.items(.shdr)[out_shndx]; |
| 1014 | 969 | out_shdr.sh_type = elf.SHT_RELA; |
| 1015 | 970 | out_shdr.sh_addralign = @alignOf(elf.Elf64_Rela); |
| ... | ... | @@ -1022,10 +977,15 @@ pub fn addAtomsToRelaSections(self: *Object, elf_file: *Elf) !void { |
| 1022 | 977 | for (self.atoms_indexes.items) |atom_index| { |
| 1023 | 978 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 1024 | 979 | if (!atom_ptr.alive) continue; |
| 980 | if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; | |
| 1025 | 981 | const shndx = blk: { |
| 1026 | 982 | const shndx = atom_ptr.relocsShndx() orelse continue; |
| 1027 | 983 | const shdr = self.shdrs.items[shndx]; |
| 1028 | break :blk self.initOutputSection(elf_file, shdr) catch unreachable; | |
| 984 | break :blk elf_file.initOutputSection(.{ | |
| 985 | .name = self.getString(shdr.sh_name), | |
| 986 | .flags = shdr.sh_flags, | |
| 987 | .type = shdr.sh_type, | |
| 988 | }) catch unreachable; | |
| 1029 | 989 | }; |
| 1030 | 990 | const slice = elf_file.sections.slice(); |
| 1031 | 991 | const shdr = &slice.items(.shdr)[shndx]; |
| ... | ... | @@ -1538,12 +1498,12 @@ fn formatComdatGroups( |
| 1538 | 1498 | } |
| 1539 | 1499 | } |
| 1540 | 1500 | |
| 1541 | pub fn fmtPath(self: *Object) std.fmt.Formatter(formatPath) { | |
| 1501 | pub fn fmtPath(self: Object) std.fmt.Formatter(formatPath) { | |
| 1542 | 1502 | return .{ .data = self }; |
| 1543 | 1503 | } |
| 1544 | 1504 | |
| 1545 | 1505 | fn formatPath( |
| 1546 | object: *Object, | |
| 1506 | object: Object, | |
| 1547 | 1507 | comptime unused_fmt_string: []const u8, |
| 1548 | 1508 | options: std.fmt.FormatOptions, |
| 1549 | 1509 | writer: anytype, |
| ... | ... | @@ -1578,6 +1538,7 @@ const mem = std.mem; |
| 1578 | 1538 | const Allocator = mem.Allocator; |
| 1579 | 1539 | const Archive = @import("Archive.zig"); |
| 1580 | 1540 | const Atom = @import("Atom.zig"); |
| 1541 | const AtomList = @import("AtomList.zig"); | |
| 1581 | 1542 | const Cie = eh_frame.Cie; |
| 1582 | 1543 | const Elf = @import("../Elf.zig"); |
| 1583 | 1544 | const Fde = eh_frame.Fde; |
src/link/Elf/ZigObject.zig+358-287| ... | ... | @@ -51,6 +51,14 @@ debug_loclists_section_dirty: bool = false, |
| 51 | 51 | debug_rnglists_section_dirty: bool = false, |
| 52 | 52 | eh_frame_section_dirty: bool = false, |
| 53 | 53 | |
| 54 | text_index: ?Symbol.Index = null, | |
| 55 | rodata_index: ?Symbol.Index = null, | |
| 56 | data_relro_index: ?Symbol.Index = null, | |
| 57 | data_index: ?Symbol.Index = null, | |
| 58 | bss_index: ?Symbol.Index = null, | |
| 59 | tdata_index: ?Symbol.Index = null, | |
| 60 | tbss_index: ?Symbol.Index = null, | |
| 61 | eh_frame_index: ?Symbol.Index = null, | |
| 54 | 62 | debug_info_index: ?Symbol.Index = null, |
| 55 | 63 | debug_abbrev_index: ?Symbol.Index = null, |
| 56 | 64 | debug_aranges_index: ?Symbol.Index = null, |
| ... | ... | @@ -59,7 +67,6 @@ debug_line_index: ?Symbol.Index = null, |
| 59 | 67 | debug_line_str_index: ?Symbol.Index = null, |
| 60 | 68 | debug_loclists_index: ?Symbol.Index = null, |
| 61 | 69 | debug_rnglists_index: ?Symbol.Index = null, |
| 62 | eh_frame_index: ?Symbol.Index = null, | |
| 63 | 70 | |
| 64 | 71 | pub const global_symbol_bit: u32 = 0x80000000; |
| 65 | 72 | pub const symbol_mask: u32 = 0x7fffffff; |
| ... | ... | @@ -71,6 +78,7 @@ const InitOptions = struct { |
| 71 | 78 | }; |
| 72 | 79 | |
| 73 | 80 | pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { |
| 81 | _ = options; | |
| 74 | 82 | const comp = elf_file.base.comp; |
| 75 | 83 | const gpa = comp.gpa; |
| 76 | 84 | const ptr_size = elf_file.ptrWidthBytes(); |
| ... | ... | @@ -88,190 +96,13 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { |
| 88 | 96 | esym.st_shndx = elf.SHN_ABS; |
| 89 | 97 | } |
| 90 | 98 | |
| 91 | const fillSection = struct { | |
| 92 | fn fillSection(ef: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) !void { | |
| 93 | if (ef.base.isRelocatable()) { | |
| 94 | const off = try ef.findFreeSpace(size, shdr.sh_addralign); | |
| 95 | shdr.sh_offset = off; | |
| 96 | shdr.sh_size = size; | |
| 97 | } else { | |
| 98 | const phdr = ef.phdrs.items[phndx.?]; | |
| 99 | shdr.sh_addr = phdr.p_vaddr; | |
| 100 | shdr.sh_offset = phdr.p_offset; | |
| 101 | shdr.sh_size = phdr.p_memsz; | |
| 102 | } | |
| 103 | } | |
| 104 | }.fillSection; | |
| 105 | ||
| 106 | comptime assert(Elf.number_of_zig_segments == 4); | |
| 107 | ||
| 108 | if (!elf_file.base.isRelocatable()) { | |
| 109 | if (elf_file.phdr_zig_load_re_index == null) { | |
| 110 | const filesz = options.program_code_size_hint; | |
| 111 | const off = try elf_file.findFreeSpace(filesz, elf_file.page_size); | |
| 112 | elf_file.phdr_zig_load_re_index = try elf_file.addPhdr(.{ | |
| 113 | .type = elf.PT_LOAD, | |
| 114 | .offset = off, | |
| 115 | .filesz = filesz, | |
| 116 | .addr = if (ptr_size >= 4) 0x4000000 else 0x4000, | |
| 117 | .memsz = filesz, | |
| 118 | .@"align" = elf_file.page_size, | |
| 119 | .flags = elf.PF_X | elf.PF_R | elf.PF_W, | |
| 120 | }); | |
| 121 | } | |
| 122 | ||
| 123 | if (elf_file.phdr_zig_load_ro_index == null) { | |
| 124 | const alignment = elf_file.page_size; | |
| 125 | const filesz: u64 = 1024; | |
| 126 | const off = try elf_file.findFreeSpace(filesz, alignment); | |
| 127 | elf_file.phdr_zig_load_ro_index = try elf_file.addPhdr(.{ | |
| 128 | .type = elf.PT_LOAD, | |
| 129 | .offset = off, | |
| 130 | .filesz = filesz, | |
| 131 | .addr = if (ptr_size >= 4) 0xc000000 else 0xa000, | |
| 132 | .memsz = filesz, | |
| 133 | .@"align" = alignment, | |
| 134 | .flags = elf.PF_R | elf.PF_W, | |
| 135 | }); | |
| 136 | } | |
| 137 | ||
| 138 | if (elf_file.phdr_zig_load_rw_index == null) { | |
| 139 | const alignment = elf_file.page_size; | |
| 140 | const filesz: u64 = 1024; | |
| 141 | const off = try elf_file.findFreeSpace(filesz, alignment); | |
| 142 | elf_file.phdr_zig_load_rw_index = try elf_file.addPhdr(.{ | |
| 143 | .type = elf.PT_LOAD, | |
| 144 | .offset = off, | |
| 145 | .filesz = filesz, | |
| 146 | .addr = if (ptr_size >= 4) 0x10000000 else 0xc000, | |
| 147 | .memsz = filesz, | |
| 148 | .@"align" = alignment, | |
| 149 | .flags = elf.PF_R | elf.PF_W, | |
| 150 | }); | |
| 151 | } | |
| 152 | ||
| 153 | if (elf_file.phdr_zig_load_zerofill_index == null) { | |
| 154 | const alignment = elf_file.page_size; | |
| 155 | elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{ | |
| 156 | .type = elf.PT_LOAD, | |
| 157 | .addr = if (ptr_size >= 4) 0x14000000 else 0xf000, | |
| 158 | .memsz = 1024, | |
| 159 | .@"align" = alignment, | |
| 160 | .flags = elf.PF_R | elf.PF_W, | |
| 161 | }); | |
| 162 | } | |
| 163 | } | |
| 164 | ||
| 165 | if (elf_file.zig_text_section_index == null) { | |
| 166 | elf_file.zig_text_section_index = try elf_file.addSection(.{ | |
| 167 | .name = try elf_file.insertShString(".text.zig"), | |
| 168 | .type = elf.SHT_PROGBITS, | |
| 169 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | |
| 170 | .addralign = 1, | |
| 171 | .offset = std.math.maxInt(u64), | |
| 172 | }); | |
| 173 | const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_text_section_index.?]; | |
| 174 | const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_text_section_index.?]; | |
| 175 | try fillSection(elf_file, shdr, options.program_code_size_hint, elf_file.phdr_zig_load_re_index); | |
| 176 | if (elf_file.base.isRelocatable()) { | |
| 177 | _ = try elf_file.addRelaShdr( | |
| 178 | try elf_file.insertShString(".rela.text.zig"), | |
| 179 | elf_file.zig_text_section_index.?, | |
| 180 | ); | |
| 181 | } else { | |
| 182 | phndx.* = elf_file.phdr_zig_load_re_index.?; | |
| 183 | } | |
| 184 | } | |
| 185 | ||
| 186 | if (elf_file.zig_data_rel_ro_section_index == null) { | |
| 187 | elf_file.zig_data_rel_ro_section_index = try elf_file.addSection(.{ | |
| 188 | .name = try elf_file.insertShString(".data.rel.ro.zig"), | |
| 189 | .type = elf.SHT_PROGBITS, | |
| 190 | .addralign = 1, | |
| 191 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 192 | .offset = std.math.maxInt(u64), | |
| 193 | }); | |
| 194 | const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_rel_ro_section_index.?]; | |
| 195 | const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_rel_ro_section_index.?]; | |
| 196 | try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_ro_index); | |
| 197 | if (elf_file.base.isRelocatable()) { | |
| 198 | _ = try elf_file.addRelaShdr( | |
| 199 | try elf_file.insertShString(".rela.data.rel.ro.zig"), | |
| 200 | elf_file.zig_data_rel_ro_section_index.?, | |
| 201 | ); | |
| 202 | } else { | |
| 203 | phndx.* = elf_file.phdr_zig_load_ro_index.?; | |
| 204 | } | |
| 205 | } | |
| 206 | ||
| 207 | if (elf_file.zig_data_section_index == null) { | |
| 208 | elf_file.zig_data_section_index = try elf_file.addSection(.{ | |
| 209 | .name = try elf_file.insertShString(".data.zig"), | |
| 210 | .type = elf.SHT_PROGBITS, | |
| 211 | .addralign = ptr_size, | |
| 212 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 213 | .offset = std.math.maxInt(u64), | |
| 214 | }); | |
| 215 | const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_section_index.?]; | |
| 216 | const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_section_index.?]; | |
| 217 | try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_rw_index); | |
| 218 | if (elf_file.base.isRelocatable()) { | |
| 219 | _ = try elf_file.addRelaShdr( | |
| 220 | try elf_file.insertShString(".rela.data.zig"), | |
| 221 | elf_file.zig_data_section_index.?, | |
| 222 | ); | |
| 223 | } else { | |
| 224 | phndx.* = elf_file.phdr_zig_load_rw_index.?; | |
| 225 | } | |
| 226 | } | |
| 227 | ||
| 228 | if (elf_file.zig_bss_section_index == null) { | |
| 229 | elf_file.zig_bss_section_index = try elf_file.addSection(.{ | |
| 230 | .name = try elf_file.insertShString(".bss.zig"), | |
| 231 | .type = elf.SHT_NOBITS, | |
| 232 | .addralign = ptr_size, | |
| 233 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 234 | .offset = 0, | |
| 235 | }); | |
| 236 | const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_bss_section_index.?]; | |
| 237 | const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_bss_section_index.?]; | |
| 238 | if (elf_file.base.isRelocatable()) { | |
| 239 | shdr.sh_size = 1024; | |
| 240 | } else { | |
| 241 | phndx.* = elf_file.phdr_zig_load_zerofill_index.?; | |
| 242 | const phdr = elf_file.phdrs.items[phndx.*.?]; | |
| 243 | shdr.sh_addr = phdr.p_vaddr; | |
| 244 | shdr.sh_size = phdr.p_memsz; | |
| 245 | } | |
| 246 | } | |
| 247 | ||
| 248 | 99 | switch (comp.config.debug_format) { |
| 249 | 100 | .strip => {}, |
| 250 | 101 | .dwarf => |v| { |
| 251 | 102 | var dwarf = Dwarf.init(&elf_file.base, v); |
| 252 | 103 | |
| 253 | const addSectionSymbol = struct { | |
| 254 | fn addSectionSymbol( | |
| 255 | zig_object: *ZigObject, | |
| 256 | alloc: Allocator, | |
| 257 | name: [:0]const u8, | |
| 258 | alignment: Atom.Alignment, | |
| 259 | shndx: u32, | |
| 260 | ) !Symbol.Index { | |
| 261 | const name_off = try zig_object.addString(alloc, name); | |
| 262 | const index = try zig_object.newSymbolWithAtom(alloc, name_off); | |
| 263 | const sym = zig_object.symbol(index); | |
| 264 | const esym = &zig_object.symtab.items(.elf_sym)[sym.esym_index]; | |
| 265 | esym.st_info |= elf.STT_SECTION; | |
| 266 | const atom_ptr = zig_object.atom(sym.ref.index).?; | |
| 267 | atom_ptr.alignment = alignment; | |
| 268 | atom_ptr.output_section_index = shndx; | |
| 269 | return index; | |
| 270 | } | |
| 271 | }.addSectionSymbol; | |
| 272 | ||
| 273 | if (elf_file.debug_str_section_index == null) { | |
| 274 | elf_file.debug_str_section_index = try elf_file.addSection(.{ | |
| 104 | if (self.debug_str_index == null) { | |
| 105 | const osec = try elf_file.addSection(.{ | |
| 275 | 106 | .name = try elf_file.insertShString(".debug_str"), |
| 276 | 107 | .flags = elf.SHF_MERGE | elf.SHF_STRINGS, |
| 277 | 108 | .entsize = 1, |
| ... | ... | @@ -279,51 +110,56 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { |
| 279 | 110 | .addralign = 1, |
| 280 | 111 | }); |
| 281 | 112 | self.debug_str_section_dirty = true; |
| 282 | self.debug_str_index = try addSectionSymbol(self, gpa, ".debug_str", .@"1", elf_file.debug_str_section_index.?); | |
| 113 | self.debug_str_index = try self.addSectionSymbol(gpa, ".debug_str", .@"1", osec); | |
| 114 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_str_index.?).ref; | |
| 283 | 115 | } |
| 284 | 116 | |
| 285 | if (elf_file.debug_info_section_index == null) { | |
| 286 | elf_file.debug_info_section_index = try elf_file.addSection(.{ | |
| 117 | if (self.debug_info_index == null) { | |
| 118 | const osec = try elf_file.addSection(.{ | |
| 287 | 119 | .name = try elf_file.insertShString(".debug_info"), |
| 288 | 120 | .type = elf.SHT_PROGBITS, |
| 289 | 121 | .addralign = 1, |
| 290 | 122 | }); |
| 291 | 123 | self.debug_info_section_dirty = true; |
| 292 | self.debug_info_index = try addSectionSymbol(self, gpa, ".debug_info", .@"1", elf_file.debug_info_section_index.?); | |
| 124 | self.debug_info_index = try self.addSectionSymbol(gpa, ".debug_info", .@"1", osec); | |
| 125 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_info_index.?).ref; | |
| 293 | 126 | } |
| 294 | 127 | |
| 295 | if (elf_file.debug_abbrev_section_index == null) { | |
| 296 | elf_file.debug_abbrev_section_index = try elf_file.addSection(.{ | |
| 128 | if (self.debug_abbrev_index == null) { | |
| 129 | const osec = try elf_file.addSection(.{ | |
| 297 | 130 | .name = try elf_file.insertShString(".debug_abbrev"), |
| 298 | 131 | .type = elf.SHT_PROGBITS, |
| 299 | 132 | .addralign = 1, |
| 300 | 133 | }); |
| 301 | 134 | self.debug_abbrev_section_dirty = true; |
| 302 | self.debug_abbrev_index = try addSectionSymbol(self, gpa, ".debug_abbrev", .@"1", elf_file.debug_abbrev_section_index.?); | |
| 135 | self.debug_abbrev_index = try self.addSectionSymbol(gpa, ".debug_abbrev", .@"1", osec); | |
| 136 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_abbrev_index.?).ref; | |
| 303 | 137 | } |
| 304 | 138 | |
| 305 | if (elf_file.debug_aranges_section_index == null) { | |
| 306 | elf_file.debug_aranges_section_index = try elf_file.addSection(.{ | |
| 139 | if (self.debug_aranges_index == null) { | |
| 140 | const osec = try elf_file.addSection(.{ | |
| 307 | 141 | .name = try elf_file.insertShString(".debug_aranges"), |
| 308 | 142 | .type = elf.SHT_PROGBITS, |
| 309 | 143 | .addralign = 16, |
| 310 | 144 | }); |
| 311 | 145 | self.debug_aranges_section_dirty = true; |
| 312 | self.debug_aranges_index = try addSectionSymbol(self, gpa, ".debug_aranges", .@"16", elf_file.debug_aranges_section_index.?); | |
| 146 | self.debug_aranges_index = try self.addSectionSymbol(gpa, ".debug_aranges", .@"16", osec); | |
| 147 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_aranges_index.?).ref; | |
| 313 | 148 | } |
| 314 | 149 | |
| 315 | if (elf_file.debug_line_section_index == null) { | |
| 316 | elf_file.debug_line_section_index = try elf_file.addSection(.{ | |
| 150 | if (self.debug_line_index == null) { | |
| 151 | const osec = try elf_file.addSection(.{ | |
| 317 | 152 | .name = try elf_file.insertShString(".debug_line"), |
| 318 | 153 | .type = elf.SHT_PROGBITS, |
| 319 | 154 | .addralign = 1, |
| 320 | 155 | }); |
| 321 | 156 | self.debug_line_section_dirty = true; |
| 322 | self.debug_line_index = try addSectionSymbol(self, gpa, ".debug_line", .@"1", elf_file.debug_line_section_index.?); | |
| 157 | self.debug_line_index = try self.addSectionSymbol(gpa, ".debug_line", .@"1", osec); | |
| 158 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_index.?).ref; | |
| 323 | 159 | } |
| 324 | 160 | |
| 325 | if (elf_file.debug_line_str_section_index == null) { | |
| 326 | elf_file.debug_line_str_section_index = try elf_file.addSection(.{ | |
| 161 | if (self.debug_line_str_index == null) { | |
| 162 | const osec = try elf_file.addSection(.{ | |
| 327 | 163 | .name = try elf_file.insertShString(".debug_line_str"), |
| 328 | 164 | .flags = elf.SHF_MERGE | elf.SHF_STRINGS, |
| 329 | 165 | .entsize = 1, |
| ... | ... | @@ -331,31 +167,34 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { |
| 331 | 167 | .addralign = 1, |
| 332 | 168 | }); |
| 333 | 169 | self.debug_line_str_section_dirty = true; |
| 334 | self.debug_line_str_index = try addSectionSymbol(self, gpa, ".debug_line_str", .@"1", elf_file.debug_line_str_section_index.?); | |
| 170 | self.debug_line_str_index = try self.addSectionSymbol(gpa, ".debug_line_str", .@"1", osec); | |
| 171 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_line_str_index.?).ref; | |
| 335 | 172 | } |
| 336 | 173 | |
| 337 | if (elf_file.debug_loclists_section_index == null) { | |
| 338 | elf_file.debug_loclists_section_index = try elf_file.addSection(.{ | |
| 174 | if (self.debug_loclists_index == null) { | |
| 175 | const osec = try elf_file.addSection(.{ | |
| 339 | 176 | .name = try elf_file.insertShString(".debug_loclists"), |
| 340 | 177 | .type = elf.SHT_PROGBITS, |
| 341 | 178 | .addralign = 1, |
| 342 | 179 | }); |
| 343 | 180 | self.debug_loclists_section_dirty = true; |
| 344 | self.debug_loclists_index = try addSectionSymbol(self, gpa, ".debug_loclists", .@"1", elf_file.debug_loclists_section_index.?); | |
| 181 | self.debug_loclists_index = try self.addSectionSymbol(gpa, ".debug_loclists", .@"1", osec); | |
| 182 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_loclists_index.?).ref; | |
| 345 | 183 | } |
| 346 | 184 | |
| 347 | if (elf_file.debug_rnglists_section_index == null) { | |
| 348 | elf_file.debug_rnglists_section_index = try elf_file.addSection(.{ | |
| 185 | if (self.debug_rnglists_index == null) { | |
| 186 | const osec = try elf_file.addSection(.{ | |
| 349 | 187 | .name = try elf_file.insertShString(".debug_rnglists"), |
| 350 | 188 | .type = elf.SHT_PROGBITS, |
| 351 | 189 | .addralign = 1, |
| 352 | 190 | }); |
| 353 | 191 | self.debug_rnglists_section_dirty = true; |
| 354 | self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?); | |
| 192 | self.debug_rnglists_index = try self.addSectionSymbol(gpa, ".debug_rnglists", .@"1", osec); | |
| 193 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.debug_rnglists_index.?).ref; | |
| 355 | 194 | } |
| 356 | 195 | |
| 357 | if (elf_file.eh_frame_section_index == null) { | |
| 358 | elf_file.eh_frame_section_index = try elf_file.addSection(.{ | |
| 196 | if (self.eh_frame_index == null) { | |
| 197 | const osec = try elf_file.addSection(.{ | |
| 359 | 198 | .name = try elf_file.insertShString(".eh_frame"), |
| 360 | 199 | .type = if (elf_file.getTarget().cpu.arch == .x86_64) |
| 361 | 200 | elf.SHT_X86_64_UNWIND |
| ... | ... | @@ -365,7 +204,8 @@ pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void { |
| 365 | 204 | .addralign = ptr_size, |
| 366 | 205 | }); |
| 367 | 206 | self.eh_frame_section_dirty = true; |
| 368 | self.eh_frame_index = try addSectionSymbol(self, gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), elf_file.eh_frame_section_index.?); | |
| 207 | self.eh_frame_index = try self.addSectionSymbol(gpa, ".eh_frame", Atom.Alignment.fromNonzeroByteUnits(ptr_size), osec); | |
| 208 | elf_file.sections.items(.last_atom)[osec] = self.symbol(self.eh_frame_index.?).ref; | |
| 369 | 209 | } |
| 370 | 210 | |
| 371 | 211 | try dwarf.initMetadata(); |
| ... | ... | @@ -404,10 +244,6 @@ pub fn deinit(self: *ZigObject, allocator: Allocator) void { |
| 404 | 244 | meta.exports.deinit(allocator); |
| 405 | 245 | } |
| 406 | 246 | self.uavs.deinit(allocator); |
| 407 | ||
| 408 | for (self.tls_variables.values()) |*tlv| { | |
| 409 | tlv.deinit(allocator); | |
| 410 | } | |
| 411 | 247 | self.tls_variables.deinit(allocator); |
| 412 | 248 | |
| 413 | 249 | if (self.dwarf) |*dwarf| { |
| ... | ... | @@ -499,12 +335,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 499 | 335 | const sym = self.symbol(sym_index); |
| 500 | 336 | const atom_ptr = self.atom(sym.ref.index).?; |
| 501 | 337 | if (!atom_ptr.alive) continue; |
| 502 | const shndx = sym.outputShndx(elf_file).?; | |
| 503 | const shdr = elf_file.sections.items(.shdr)[shndx]; | |
| 504 | const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; | |
| 505 | esym.st_size = shdr.sh_size; | |
| 506 | atom_ptr.size = shdr.sh_size; | |
| 507 | atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); | |
| 508 | 338 | |
| 509 | 339 | log.debug("parsing relocs in {s}", .{sym.name(elf_file)}); |
| 510 | 340 | |
| ... | ... | @@ -665,14 +495,6 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 665 | 495 | } |
| 666 | 496 | } |
| 667 | 497 | } |
| 668 | ||
| 669 | if (elf_file.base.isRelocatable() and relocs.items.len > 0) { | |
| 670 | const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{elf_file.getShString(shdr.sh_name)}); | |
| 671 | defer gpa.free(rela_sect_name); | |
| 672 | if (elf_file.sectionByName(rela_sect_name) == null) { | |
| 673 | _ = try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), shndx); | |
| 674 | } | |
| 675 | } | |
| 676 | 498 | } |
| 677 | 499 | |
| 678 | 500 | self.debug_abbrev_section_dirty = false; |
| ... | ... | @@ -835,7 +657,7 @@ pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void { |
| 835 | 657 | } |
| 836 | 658 | } |
| 837 | 659 | |
| 838 | pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void { | |
| 660 | pub fn claimUnresolvedRelocatable(self: ZigObject, elf_file: *Elf) void { | |
| 839 | 661 | for (self.global_symbols.items, 0..) |index, i| { |
| 840 | 662 | const global = &self.symbols.items[index]; |
| 841 | 663 | const esym = self.symtab.items(.elf_sym)[index]; |
| ... | ... | @@ -990,21 +812,48 @@ pub fn writeAr(self: ZigObject, writer: anytype) !void { |
| 990 | 812 | try writer.writeAll(self.data.items); |
| 991 | 813 | } |
| 992 | 814 | |
| 815 | pub fn initRelaSections(self: *ZigObject, elf_file: *Elf) !void { | |
| 816 | const gpa = elf_file.base.comp.gpa; | |
| 817 | for (self.atoms_indexes.items) |atom_index| { | |
| 818 | const atom_ptr = self.atom(atom_index) orelse continue; | |
| 819 | if (!atom_ptr.alive) continue; | |
| 820 | if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; | |
| 821 | const rela_shndx = atom_ptr.relocsShndx() orelse continue; | |
| 822 | // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level | |
| 823 | if (self.relocs.items[rela_shndx].items.len == 0) continue; | |
| 824 | const out_shndx = atom_ptr.output_section_index; | |
| 825 | const out_shdr = elf_file.sections.items(.shdr)[out_shndx]; | |
| 826 | if (out_shdr.sh_type == elf.SHT_NOBITS) continue; | |
| 827 | const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{ | |
| 828 | elf_file.getShString(out_shdr.sh_name), | |
| 829 | }); | |
| 830 | defer gpa.free(rela_sect_name); | |
| 831 | _ = elf_file.sectionByName(rela_sect_name) orelse | |
| 832 | try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), out_shndx); | |
| 833 | } | |
| 834 | } | |
| 835 | ||
| 993 | 836 | pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void { |
| 837 | const gpa = elf_file.base.comp.gpa; | |
| 994 | 838 | for (self.atoms_indexes.items) |atom_index| { |
| 995 | 839 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 996 | 840 | if (!atom_ptr.alive) continue; |
| 841 | if (atom_ptr.output_section_index == elf_file.eh_frame_section_index) continue; | |
| 997 | 842 | const rela_shndx = atom_ptr.relocsShndx() orelse continue; |
| 998 | 843 | // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level |
| 999 | 844 | if (self.relocs.items[rela_shndx].items.len == 0) continue; |
| 1000 | 845 | const out_shndx = atom_ptr.output_section_index; |
| 1001 | 846 | const out_shdr = elf_file.sections.items(.shdr)[out_shndx]; |
| 1002 | 847 | if (out_shdr.sh_type == elf.SHT_NOBITS) continue; |
| 1003 | const out_rela_shndx = for (elf_file.sections.items(.shdr), 0..) |out_rela_shdr, out_rela_shndx| { | |
| 1004 | if (out_rela_shdr.sh_type == elf.SHT_RELA and out_rela_shdr.sh_info == out_shndx) break out_rela_shndx; | |
| 1005 | } else unreachable; | |
| 848 | const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{ | |
| 849 | elf_file.getShString(out_shdr.sh_name), | |
| 850 | }); | |
| 851 | defer gpa.free(rela_sect_name); | |
| 852 | const out_rela_shndx = elf_file.sectionByName(rela_sect_name).?; | |
| 853 | const out_rela_shdr = &elf_file.sections.items(.shdr)[out_rela_shndx]; | |
| 854 | out_rela_shdr.sh_info = out_shndx; | |
| 855 | out_rela_shdr.sh_link = elf_file.symtab_section_index.?; | |
| 1006 | 856 | const atom_list = &elf_file.sections.items(.atom_list)[out_rela_shndx]; |
| 1007 | const gpa = elf_file.base.comp.gpa; | |
| 1008 | 857 | try atom_list.append(gpa, .{ .index = atom_index, .file = self.index }); |
| 1009 | 858 | } |
| 1010 | 859 | } |
| ... | ... | @@ -1075,15 +924,7 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void { |
| 1075 | 924 | pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 { |
| 1076 | 925 | const gpa = elf_file.base.comp.gpa; |
| 1077 | 926 | const atom_ptr = self.atom(atom_index).?; |
| 1078 | const shdr = &elf_file.sections.items(.shdr)[atom_ptr.output_section_index]; | |
| 1079 | ||
| 1080 | if (shdr.sh_flags & elf.SHF_TLS != 0) { | |
| 1081 | const tlv = self.tls_variables.get(atom_index).?; | |
| 1082 | const code = try gpa.dupe(u8, tlv.code); | |
| 1083 | return code; | |
| 1084 | } | |
| 1085 | ||
| 1086 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 927 | const file_offset = atom_ptr.offset(elf_file); | |
| 1087 | 928 | const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 1088 | 929 | const code = try gpa.alloc(u8, size); |
| 1089 | 930 | errdefer gpa.free(code); |
| ... | ... | @@ -1168,6 +1009,20 @@ pub fn lowerUav( |
| 1168 | 1009 | return .{ .mcv = .{ .load_symbol = metadata.symbol_index } }; |
| 1169 | 1010 | } |
| 1170 | 1011 | |
| 1012 | const osec = if (self.data_relro_index) |sym_index| | |
| 1013 | self.symbol(sym_index).atom(elf_file).?.output_section_index | |
| 1014 | else osec: { | |
| 1015 | const osec = try elf_file.addSection(.{ | |
| 1016 | .name = try elf_file.insertShString(".data.rel.ro"), | |
| 1017 | .type = elf.SHT_PROGBITS, | |
| 1018 | .addralign = 1, | |
| 1019 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 1020 | .offset = std.math.maxInt(u64), | |
| 1021 | }); | |
| 1022 | self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec); | |
| 1023 | break :osec osec; | |
| 1024 | }; | |
| 1025 | ||
| 1171 | 1026 | var name_buf: [32]u8 = undefined; |
| 1172 | 1027 | const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{ |
| 1173 | 1028 | @intFromEnum(uav), |
| ... | ... | @@ -1178,7 +1033,7 @@ pub fn lowerUav( |
| 1178 | 1033 | name, |
| 1179 | 1034 | val, |
| 1180 | 1035 | uav_alignment, |
| 1181 | elf_file.zig_data_rel_ro_section_index.?, | |
| 1036 | osec, | |
| 1182 | 1037 | src_loc, |
| 1183 | 1038 | ) catch |err| switch (err) { |
| 1184 | 1039 | error.OutOfMemory => return error.OutOfMemory, |
| ... | ... | @@ -1270,6 +1125,27 @@ pub fn getOrCreateMetadataForNav( |
| 1270 | 1125 | return gop.value_ptr.symbol_index; |
| 1271 | 1126 | } |
| 1272 | 1127 | |
| 1128 | // FIXME: we always create an atom to basically store size and alignment, however, this is only true for | |
| 1129 | // sections that have a single atom like the debug sections. It would be a better solution to decouple this | |
| 1130 | // concept from the atom, maybe. | |
| 1131 | fn addSectionSymbol( | |
| 1132 | self: *ZigObject, | |
| 1133 | allocator: Allocator, | |
| 1134 | name: [:0]const u8, | |
| 1135 | alignment: Atom.Alignment, | |
| 1136 | shndx: u32, | |
| 1137 | ) !Symbol.Index { | |
| 1138 | const name_off = try self.addString(allocator, name); | |
| 1139 | const index = try self.newSymbolWithAtom(allocator, name_off); | |
| 1140 | const sym = self.symbol(index); | |
| 1141 | const esym = &self.symtab.items(.elf_sym)[sym.esym_index]; | |
| 1142 | esym.st_info |= elf.STT_SECTION; | |
| 1143 | const atom_ptr = self.atom(sym.ref.index).?; | |
| 1144 | atom_ptr.alignment = alignment; | |
| 1145 | atom_ptr.output_section_index = shndx; | |
| 1146 | return index; | |
| 1147 | } | |
| 1148 | ||
| 1273 | 1149 | fn getNavShdrIndex( |
| 1274 | 1150 | self: *ZigObject, |
| 1275 | 1151 | elf_file: *Elf, |
| ... | ... | @@ -1278,10 +1154,24 @@ fn getNavShdrIndex( |
| 1278 | 1154 | sym_index: Symbol.Index, |
| 1279 | 1155 | code: []const u8, |
| 1280 | 1156 | ) error{OutOfMemory}!u32 { |
| 1157 | const gpa = elf_file.base.comp.gpa; | |
| 1158 | const ptr_size = elf_file.ptrWidthBytes(); | |
| 1281 | 1159 | const ip = &zcu.intern_pool; |
| 1282 | 1160 | const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded; |
| 1283 | 1161 | const nav_val = zcu.navValue(nav_index); |
| 1284 | if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return elf_file.zig_text_section_index.?; | |
| 1162 | if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) { | |
| 1163 | if (self.text_index) |symbol_index| | |
| 1164 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1165 | const osec = try elf_file.addSection(.{ | |
| 1166 | .type = elf.SHT_PROGBITS, | |
| 1167 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | |
| 1168 | .name = try elf_file.insertShString(".text"), | |
| 1169 | .addralign = 1, | |
| 1170 | .offset = std.math.maxInt(u64), | |
| 1171 | }); | |
| 1172 | self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec); | |
| 1173 | return osec; | |
| 1174 | } | |
| 1285 | 1175 | const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) { |
| 1286 | 1176 | .variable => |variable| .{ false, variable.is_threadlocal, variable.init }, |
| 1287 | 1177 | .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none }, |
| ... | ... | @@ -1292,30 +1182,107 @@ fn getNavShdrIndex( |
| 1292 | 1182 | const is_bss = !has_relocs and for (code) |byte| { |
| 1293 | 1183 | if (byte != 0) break false; |
| 1294 | 1184 | } else true; |
| 1295 | if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{ | |
| 1296 | .type = elf.SHT_NOBITS, | |
| 1185 | if (is_bss) { | |
| 1186 | if (self.tbss_index) |symbol_index| | |
| 1187 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1188 | const osec = try elf_file.addSection(.{ | |
| 1189 | .name = try elf_file.insertShString(".tbss"), | |
| 1190 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, | |
| 1191 | .type = elf.SHT_NOBITS, | |
| 1192 | .addralign = 1, | |
| 1193 | }); | |
| 1194 | self.tbss_index = try self.addSectionSymbol(gpa, ".tbss", .@"1", osec); | |
| 1195 | return osec; | |
| 1196 | } | |
| 1197 | if (self.tdata_index) |symbol_index| | |
| 1198 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1199 | const osec = try elf_file.addSection(.{ | |
| 1200 | .type = elf.SHT_PROGBITS, | |
| 1297 | 1201 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, |
| 1298 | .name = try elf_file.insertShString(".tbss"), | |
| 1202 | .name = try elf_file.insertShString(".tdata"), | |
| 1203 | .addralign = 1, | |
| 1299 | 1204 | .offset = std.math.maxInt(u64), |
| 1300 | 1205 | }); |
| 1301 | return elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{ | |
| 1206 | self.tdata_index = try self.addSectionSymbol(gpa, ".tdata", .@"1", osec); | |
| 1207 | return osec; | |
| 1208 | } | |
| 1209 | if (is_const) { | |
| 1210 | if (self.data_relro_index) |symbol_index| | |
| 1211 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1212 | const osec = try elf_file.addSection(.{ | |
| 1213 | .name = try elf_file.insertShString(".data.rel.ro"), | |
| 1302 | 1214 | .type = elf.SHT_PROGBITS, |
| 1303 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS, | |
| 1304 | .name = try elf_file.insertShString(".tdata"), | |
| 1215 | .addralign = 1, | |
| 1216 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 1305 | 1217 | .offset = std.math.maxInt(u64), |
| 1306 | 1218 | }); |
| 1219 | self.data_relro_index = try self.addSectionSymbol(gpa, ".data.rel.ro", .@"1", osec); | |
| 1220 | return osec; | |
| 1307 | 1221 | } |
| 1308 | if (is_const) return elf_file.zig_data_rel_ro_section_index.?; | |
| 1309 | 1222 | if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu)) |
| 1310 | 1223 | return switch (zcu.navFileScope(nav_index).mod.optimize_mode) { |
| 1311 | .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?, | |
| 1312 | .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?, | |
| 1224 | .Debug, .ReleaseSafe => { | |
| 1225 | if (self.data_index) |symbol_index| | |
| 1226 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1227 | const osec = try elf_file.addSection(.{ | |
| 1228 | .name = try elf_file.insertShString(".data"), | |
| 1229 | .type = elf.SHT_PROGBITS, | |
| 1230 | .addralign = ptr_size, | |
| 1231 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 1232 | .offset = std.math.maxInt(u64), | |
| 1233 | }); | |
| 1234 | self.data_index = try self.addSectionSymbol( | |
| 1235 | gpa, | |
| 1236 | ".data", | |
| 1237 | Atom.Alignment.fromNonzeroByteUnits(ptr_size), | |
| 1238 | osec, | |
| 1239 | ); | |
| 1240 | return osec; | |
| 1241 | }, | |
| 1242 | .ReleaseFast, .ReleaseSmall => { | |
| 1243 | if (self.bss_index) |symbol_index| | |
| 1244 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1245 | const osec = try elf_file.addSection(.{ | |
| 1246 | .type = elf.SHT_NOBITS, | |
| 1247 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 1248 | .name = try elf_file.insertShString(".bss"), | |
| 1249 | .addralign = 1, | |
| 1250 | }); | |
| 1251 | self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec); | |
| 1252 | return osec; | |
| 1253 | }, | |
| 1313 | 1254 | }; |
| 1314 | 1255 | const is_bss = !has_relocs and for (code) |byte| { |
| 1315 | 1256 | if (byte != 0) break false; |
| 1316 | 1257 | } else true; |
| 1317 | if (is_bss) return elf_file.zig_bss_section_index.?; | |
| 1318 | return elf_file.zig_data_section_index.?; | |
| 1258 | if (is_bss) { | |
| 1259 | if (self.bss_index) |symbol_index| | |
| 1260 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1261 | const osec = try elf_file.addSection(.{ | |
| 1262 | .type = elf.SHT_NOBITS, | |
| 1263 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 1264 | .name = try elf_file.insertShString(".bss"), | |
| 1265 | .addralign = 1, | |
| 1266 | }); | |
| 1267 | self.bss_index = try self.addSectionSymbol(gpa, ".bss", .@"1", osec); | |
| 1268 | return osec; | |
| 1269 | } | |
| 1270 | if (self.data_index) |symbol_index| | |
| 1271 | return self.symbol(symbol_index).atom(elf_file).?.output_section_index; | |
| 1272 | const osec = try elf_file.addSection(.{ | |
| 1273 | .name = try elf_file.insertShString(".data"), | |
| 1274 | .type = elf.SHT_PROGBITS, | |
| 1275 | .addralign = ptr_size, | |
| 1276 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, | |
| 1277 | .offset = std.math.maxInt(u64), | |
| 1278 | }); | |
| 1279 | self.data_index = try self.addSectionSymbol( | |
| 1280 | gpa, | |
| 1281 | ".data", | |
| 1282 | Atom.Alignment.fromNonzeroByteUnits(ptr_size), | |
| 1283 | osec, | |
| 1284 | ); | |
| 1285 | return osec; | |
| 1319 | 1286 | } |
| 1320 | 1287 | |
| 1321 | 1288 | fn updateNavCode( |
| ... | ... | @@ -1362,19 +1329,18 @@ fn updateNavCode( |
| 1362 | 1329 | const capacity = atom_ptr.capacity(elf_file); |
| 1363 | 1330 | const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value)); |
| 1364 | 1331 | if (need_realloc) { |
| 1365 | try atom_ptr.grow(elf_file); | |
| 1332 | try self.growAtom(atom_ptr, elf_file); | |
| 1366 | 1333 | log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value }); |
| 1367 | 1334 | if (old_vaddr != atom_ptr.value) { |
| 1368 | 1335 | sym.value = 0; |
| 1369 | 1336 | esym.st_value = 0; |
| 1370 | 1337 | } |
| 1371 | 1338 | } else if (code.len < old_size) { |
| 1372 | atom_ptr.shrink(elf_file); | |
| 1339 | // TODO shrink section size | |
| 1373 | 1340 | } |
| 1374 | 1341 | } else { |
| 1375 | try atom_ptr.allocate(elf_file); | |
| 1342 | try self.allocateAtom(atom_ptr, elf_file); | |
| 1376 | 1343 | errdefer self.freeNavMetadata(elf_file, sym_index); |
| 1377 | ||
| 1378 | 1344 | sym.value = 0; |
| 1379 | 1345 | esym.st_value = 0; |
| 1380 | 1346 | } |
| ... | ... | @@ -1404,7 +1370,7 @@ fn updateNavCode( |
| 1404 | 1370 | |
| 1405 | 1371 | const shdr = elf_file.sections.items(.shdr)[shdr_index]; |
| 1406 | 1372 | if (shdr.sh_type != elf.SHT_NOBITS) { |
| 1407 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 1373 | const file_offset = atom_ptr.offset(elf_file); | |
| 1408 | 1374 | try elf_file.base.file.?.pwriteAll(code, file_offset); |
| 1409 | 1375 | log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len }); |
| 1410 | 1376 | } |
| ... | ... | @@ -1433,15 +1399,11 @@ fn updateTlv( |
| 1433 | 1399 | const atom_ptr = sym.atom(elf_file).?; |
| 1434 | 1400 | const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip)); |
| 1435 | 1401 | |
| 1436 | sym.value = 0; | |
| 1437 | sym.name_offset = name_offset; | |
| 1438 | ||
| 1439 | atom_ptr.output_section_index = shndx; | |
| 1440 | 1402 | atom_ptr.alive = true; |
| 1441 | 1403 | atom_ptr.name_offset = name_offset; |
| 1404 | atom_ptr.output_section_index = shndx; | |
| 1442 | 1405 | |
| 1443 | 1406 | sym.name_offset = name_offset; |
| 1444 | esym.st_value = 0; | |
| 1445 | 1407 | esym.st_name = name_offset; |
| 1446 | 1408 | esym.st_info = elf.STT_TLS; |
| 1447 | 1409 | esym.st_size = code.len; |
| ... | ... | @@ -1449,21 +1411,25 @@ fn updateTlv( |
| 1449 | 1411 | atom_ptr.alignment = required_alignment; |
| 1450 | 1412 | atom_ptr.size = code.len; |
| 1451 | 1413 | |
| 1452 | self.navs.getPtr(nav_index).?.allocated = true; | |
| 1414 | const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); | |
| 1415 | assert(!gop.found_existing); // TODO incremental updates | |
| 1453 | 1416 | |
| 1454 | { | |
| 1455 | const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index); | |
| 1456 | assert(!gop.found_existing); // TODO incremental updates | |
| 1457 | gop.value_ptr.* = .{ .symbol_index = sym_index }; | |
| 1417 | try self.allocateAtom(atom_ptr, elf_file); | |
| 1418 | sym.value = 0; | |
| 1419 | esym.st_value = 0; | |
| 1458 | 1420 | |
| 1459 | // We only store the data for the TLV if it's non-zerofill. | |
| 1460 | if (elf_file.sections.items(.shdr)[shndx].sh_type != elf.SHT_NOBITS) { | |
| 1461 | gop.value_ptr.code = try gpa.dupe(u8, code); | |
| 1462 | } | |
| 1463 | } | |
| 1421 | self.navs.getPtr(nav_index).?.allocated = true; | |
| 1464 | 1422 | |
| 1465 | const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index]; | |
| 1466 | try atom_list.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index }); | |
| 1423 | const shdr = elf_file.sections.items(.shdr)[shndx]; | |
| 1424 | if (shdr.sh_type != elf.SHT_NOBITS) { | |
| 1425 | const file_offset = atom_ptr.offset(elf_file); | |
| 1426 | try elf_file.base.file.?.pwriteAll(code, file_offset); | |
| 1427 | log.debug("writing TLV {s} from 0x{x} to 0x{x}", .{ | |
| 1428 | atom_ptr.name(elf_file), | |
| 1429 | file_offset, | |
| 1430 | file_offset + code.len, | |
| 1431 | }); | |
| 1432 | } | |
| 1467 | 1433 | } |
| 1468 | 1434 | |
| 1469 | 1435 | pub fn updateFunc( |
| ... | ... | @@ -1558,6 +1524,19 @@ pub fn updateFunc( |
| 1558 | 1524 | self.symbol(sym_index).name(elf_file), |
| 1559 | 1525 | }); |
| 1560 | 1526 | defer gpa.free(name); |
| 1527 | const osec = if (self.text_index) |sect_sym_index| | |
| 1528 | self.symbol(sect_sym_index).atom(elf_file).?.output_section_index | |
| 1529 | else osec: { | |
| 1530 | const osec = try elf_file.addSection(.{ | |
| 1531 | .name = try elf_file.insertShString(".text"), | |
| 1532 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | |
| 1533 | .type = elf.SHT_PROGBITS, | |
| 1534 | .addralign = 1, | |
| 1535 | .offset = std.math.maxInt(u64), | |
| 1536 | }); | |
| 1537 | self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec); | |
| 1538 | break :osec osec; | |
| 1539 | }; | |
| 1561 | 1540 | const name_off = try self.addString(gpa, name); |
| 1562 | 1541 | const tr_size = trampolineSize(elf_file.getTarget().cpu.arch); |
| 1563 | 1542 | const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off); |
| ... | ... | @@ -1569,7 +1548,7 @@ pub fn updateFunc( |
| 1569 | 1548 | tr_atom_ptr.value = old_rva; |
| 1570 | 1549 | tr_atom_ptr.alive = true; |
| 1571 | 1550 | tr_atom_ptr.alignment = old_alignment; |
| 1572 | tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?; | |
| 1551 | tr_atom_ptr.output_section_index = osec; | |
| 1573 | 1552 | tr_atom_ptr.size = tr_size; |
| 1574 | 1553 | const target_sym = self.symbol(sym_index); |
| 1575 | 1554 | target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file); |
| ... | ... | @@ -1723,8 +1702,32 @@ fn updateLazySymbol( |
| 1723 | 1702 | }; |
| 1724 | 1703 | |
| 1725 | 1704 | const output_section_index = switch (sym.kind) { |
| 1726 | .code => elf_file.zig_text_section_index.?, | |
| 1727 | .const_data => elf_file.zig_data_rel_ro_section_index.?, | |
| 1705 | .code => if (self.text_index) |sym_index| | |
| 1706 | self.symbol(sym_index).atom(elf_file).?.output_section_index | |
| 1707 | else osec: { | |
| 1708 | const osec = try elf_file.addSection(.{ | |
| 1709 | .name = try elf_file.insertShString(".text"), | |
| 1710 | .type = elf.SHT_PROGBITS, | |
| 1711 | .addralign = 1, | |
| 1712 | .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR, | |
| 1713 | .offset = std.math.maxInt(u64), | |
| 1714 | }); | |
| 1715 | self.text_index = try self.addSectionSymbol(gpa, ".text", .@"1", osec); | |
| 1716 | break :osec osec; | |
| 1717 | }, | |
| 1718 | .const_data => if (self.rodata_index) |sym_index| | |
| 1719 | self.symbol(sym_index).atom(elf_file).?.output_section_index | |
| 1720 | else osec: { | |
| 1721 | const osec = try elf_file.addSection(.{ | |
| 1722 | .name = try elf_file.insertShString(".rodata"), | |
| 1723 | .type = elf.SHT_PROGBITS, | |
| 1724 | .addralign = 1, | |
| 1725 | .flags = elf.SHF_ALLOC, | |
| 1726 | .offset = std.math.maxInt(u64), | |
| 1727 | }); | |
| 1728 | self.rodata_index = try self.addSectionSymbol(gpa, ".rodata", .@"1", osec); | |
| 1729 | break :osec osec; | |
| 1730 | }, | |
| 1728 | 1731 | }; |
| 1729 | 1732 | const local_sym = self.symbol(symbol_index); |
| 1730 | 1733 | local_sym.name_offset = name_str_index; |
| ... | ... | @@ -1739,15 +1742,13 @@ fn updateLazySymbol( |
| 1739 | 1742 | atom_ptr.size = code.len; |
| 1740 | 1743 | atom_ptr.output_section_index = output_section_index; |
| 1741 | 1744 | |
| 1742 | try atom_ptr.allocate(elf_file); | |
| 1745 | try self.allocateAtom(atom_ptr, elf_file); | |
| 1743 | 1746 | errdefer self.freeNavMetadata(elf_file, symbol_index); |
| 1744 | 1747 | |
| 1745 | 1748 | local_sym.value = 0; |
| 1746 | 1749 | local_esym.st_value = 0; |
| 1747 | 1750 | |
| 1748 | const shdr = elf_file.sections.items(.shdr)[output_section_index]; | |
| 1749 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 1750 | try elf_file.base.file.?.pwriteAll(code, file_offset); | |
| 1751 | try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file)); | |
| 1751 | 1752 | } |
| 1752 | 1753 | |
| 1753 | 1754 | const LowerConstResult = union(enum) { |
| ... | ... | @@ -1797,13 +1798,10 @@ fn lowerConst( |
| 1797 | 1798 | atom_ptr.size = code.len; |
| 1798 | 1799 | atom_ptr.output_section_index = output_section_index; |
| 1799 | 1800 | |
| 1800 | try atom_ptr.allocate(elf_file); | |
| 1801 | // TODO rename and re-audit this method | |
| 1801 | try self.allocateAtom(atom_ptr, elf_file); | |
| 1802 | 1802 | errdefer self.freeNavMetadata(elf_file, sym_index); |
| 1803 | 1803 | |
| 1804 | const shdr = elf_file.sections.items(.shdr)[output_section_index]; | |
| 1805 | const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 1806 | try elf_file.base.file.?.pwriteAll(code, file_offset); | |
| 1804 | try elf_file.base.file.?.pwriteAll(code, atom_ptr.offset(elf_file)); | |
| 1807 | 1805 | |
| 1808 | 1806 | return .{ .ok = sym_index }; |
| 1809 | 1807 | } |
| ... | ... | @@ -1965,8 +1963,7 @@ fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { |
| 1965 | 1963 | |
| 1966 | 1964 | fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { |
| 1967 | 1965 | const atom_ptr = tr_sym.atom(elf_file).?; |
| 1968 | const shdr = elf_file.sections.items(.shdr)[atom_ptr.output_section_index]; | |
| 1969 | const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value)); | |
| 1966 | const fileoff = atom_ptr.offset(elf_file); | |
| 1970 | 1967 | const source_addr = tr_sym.address(.{}, elf_file); |
| 1971 | 1968 | const target_addr = target.address(.{ .trampoline = false }, elf_file); |
| 1972 | 1969 | var buf: [max_trampoline_len]u8 = undefined; |
| ... | ... | @@ -1998,6 +1995,80 @@ fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void { |
| 1998 | 1995 | } |
| 1999 | 1996 | } |
| 2000 | 1997 | |
| 1998 | fn allocateAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { | |
| 1999 | const alloc_res = try elf_file.allocateChunk(.{ | |
| 2000 | .shndx = atom_ptr.output_section_index, | |
| 2001 | .size = atom_ptr.size, | |
| 2002 | .alignment = atom_ptr.alignment, | |
| 2003 | }); | |
| 2004 | atom_ptr.value = @intCast(alloc_res.value); | |
| 2005 | ||
| 2006 | const slice = elf_file.sections.slice(); | |
| 2007 | const shdr = &slice.items(.shdr)[atom_ptr.output_section_index]; | |
| 2008 | const last_atom_ref = &slice.items(.last_atom)[atom_ptr.output_section_index]; | |
| 2009 | ||
| 2010 | const expand_section = if (elf_file.atom(alloc_res.placement)) |placement_atom| | |
| 2011 | placement_atom.nextAtom(elf_file) == null | |
| 2012 | else | |
| 2013 | true; | |
| 2014 | if (expand_section) { | |
| 2015 | last_atom_ref.* = atom_ptr.ref(); | |
| 2016 | if (self.dwarf) |_| { | |
| 2017 | // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address | |
| 2018 | // range of the compilation unit. When we expand the text section, this range changes, | |
| 2019 | // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. | |
| 2020 | self.debug_info_section_dirty = true; | |
| 2021 | // This becomes dirty for the same reason. We could potentially make this more | |
| 2022 | // fine-grained with the addition of support for more compilation units. It is planned to | |
| 2023 | // model each package as a different compilation unit. | |
| 2024 | self.debug_aranges_section_dirty = true; | |
| 2025 | self.debug_rnglists_section_dirty = true; | |
| 2026 | } | |
| 2027 | } | |
| 2028 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits().?); | |
| 2029 | ||
| 2030 | const sect_atom_ptr = for ([_]?Symbol.Index{ | |
| 2031 | self.text_index, | |
| 2032 | self.rodata_index, | |
| 2033 | self.data_relro_index, | |
| 2034 | self.data_index, | |
| 2035 | self.tdata_index, | |
| 2036 | }) |maybe_sym_index| { | |
| 2037 | const sect_sym_index = maybe_sym_index orelse continue; | |
| 2038 | const sect_atom_ptr = self.symbol(sect_sym_index).atom(elf_file).?; | |
| 2039 | if (sect_atom_ptr.output_section_index == atom_ptr.output_section_index) break sect_atom_ptr; | |
| 2040 | } else null; | |
| 2041 | if (sect_atom_ptr) |sap| { | |
| 2042 | sap.size = shdr.sh_size; | |
| 2043 | sap.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign); | |
| 2044 | } | |
| 2045 | ||
| 2046 | // This function can also reallocate an atom. | |
| 2047 | // In this case we need to "unplug" it from its previous location before | |
| 2048 | // plugging it in to its new location. | |
| 2049 | if (atom_ptr.prevAtom(elf_file)) |prev| { | |
| 2050 | prev.next_atom_ref = atom_ptr.next_atom_ref; | |
| 2051 | } | |
| 2052 | if (atom_ptr.nextAtom(elf_file)) |next| { | |
| 2053 | next.prev_atom_ref = atom_ptr.prev_atom_ref; | |
| 2054 | } | |
| 2055 | ||
| 2056 | if (elf_file.atom(alloc_res.placement)) |big_atom| { | |
| 2057 | atom_ptr.prev_atom_ref = alloc_res.placement; | |
| 2058 | atom_ptr.next_atom_ref = big_atom.next_atom_ref; | |
| 2059 | big_atom.next_atom_ref = atom_ptr.ref(); | |
| 2060 | } else { | |
| 2061 | atom_ptr.prev_atom_ref = .{ .index = 0, .file = 0 }; | |
| 2062 | atom_ptr.next_atom_ref = .{ .index = 0, .file = 0 }; | |
| 2063 | } | |
| 2064 | } | |
| 2065 | ||
| 2066 | fn growAtom(self: *ZigObject, atom_ptr: *Atom, elf_file: *Elf) !void { | |
| 2067 | if (!atom_ptr.alignment.check(@intCast(atom_ptr.value)) or atom_ptr.size > atom_ptr.capacity(elf_file)) { | |
| 2068 | try self.allocateAtom(atom_ptr, elf_file); | |
| 2069 | } | |
| 2070 | } | |
| 2071 | ||
| 2001 | 2072 | pub fn asFile(self: *ZigObject) File { |
| 2002 | 2073 | return .{ .zig_object = self }; |
| 2003 | 2074 | } |
| ... | ... | @@ -2271,7 +2342,7 @@ const AtomList = std.ArrayListUnmanaged(Atom.Index); |
| 2271 | 2342 | const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata); |
| 2272 | 2343 | const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata); |
| 2273 | 2344 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata); |
| 2274 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable); | |
| 2345 | const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, void); | |
| 2275 | 2346 | |
| 2276 | 2347 | const x86_64 = struct { |
| 2277 | 2348 | fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 { |
src/link/Elf/eh_frame.zig+30-6| ... | ... | @@ -233,7 +233,10 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize { |
| 233 | 233 | const comp = elf_file.base.comp; |
| 234 | 234 | const gpa = comp.gpa; |
| 235 | 235 | |
| 236 | var offset: usize = 0; | |
| 236 | var offset: usize = if (elf_file.zigObjectPtr()) |zo| blk: { | |
| 237 | const sym = zo.symbol(zo.eh_frame_index orelse break :blk 0); | |
| 238 | break :blk math.cast(usize, sym.atom(elf_file).?.size) orelse return error.Overflow; | |
| 239 | } else 0; | |
| 237 | 240 | |
| 238 | 241 | var cies = std.ArrayList(Cie).init(gpa); |
| 239 | 242 | defer cies.deinit(); |
| ... | ... | @@ -288,6 +291,13 @@ pub fn calcEhFrameHdrSize(elf_file: *Elf) usize { |
| 288 | 291 | |
| 289 | 292 | pub fn calcEhFrameRelocs(elf_file: *Elf) usize { |
| 290 | 293 | var count: usize = 0; |
| 294 | if (elf_file.zigObjectPtr()) |zo| zo: { | |
| 295 | const sym_index = zo.eh_frame_index orelse break :zo; | |
| 296 | const sym = zo.symbol(sym_index); | |
| 297 | const atom_ptr = zo.atom(sym.ref.index).?; | |
| 298 | if (!atom_ptr.alive) break :zo; | |
| 299 | count += atom_ptr.relocs(elf_file).len; | |
| 300 | } | |
| 291 | 301 | for (elf_file.objects.items) |index| { |
| 292 | 302 | const object = elf_file.file(index).?.object; |
| 293 | 303 | for (object.cies.items) |cie| { |
| ... | ... | @@ -386,7 +396,7 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void { |
| 386 | 396 | if (has_reloc_errors) return error.RelocFailure; |
| 387 | 397 | } |
| 388 | 398 | |
| 389 | pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { | |
| 399 | pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void { | |
| 390 | 400 | for (elf_file.objects.items) |index| { |
| 391 | 401 | const object = elf_file.file(index).?.object; |
| 392 | 402 | |
| ... | ... | @@ -416,9 +426,8 @@ pub fn writeEhFrameObject(elf_file: *Elf, writer: anytype) !void { |
| 416 | 426 | } |
| 417 | 427 | } |
| 418 | 428 | |
| 419 | fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { | |
| 429 | fn emitReloc(elf_file: *Elf, r_offset: u64, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela { | |
| 420 | 430 | const cpu_arch = elf_file.getTarget().cpu.arch; |
| 421 | const r_offset = rec.address(elf_file) + rel.r_offset - rec.offset; | |
| 422 | 431 | const r_type = rel.r_type(); |
| 423 | 432 | var r_addend = rel.r_addend; |
| 424 | 433 | var r_sym: u32 = 0; |
| ... | ... | @@ -452,6 +461,19 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { |
| 452 | 461 | elf_file.sections.items(.shdr)[elf_file.eh_frame_section_index.?].sh_addr, |
| 453 | 462 | }); |
| 454 | 463 | |
| 464 | if (elf_file.zigObjectPtr()) |zo| zo: { | |
| 465 | const sym_index = zo.eh_frame_index orelse break :zo; | |
| 466 | const sym = zo.symbol(sym_index); | |
| 467 | const atom_ptr = zo.atom(sym.ref.index).?; | |
| 468 | if (!atom_ptr.alive) break :zo; | |
| 469 | for (atom_ptr.relocs(elf_file)) |rel| { | |
| 470 | const ref = zo.resolveSymbol(rel.r_sym(), elf_file); | |
| 471 | const target = elf_file.symbol(ref).?; | |
| 472 | const out_rel = emitReloc(elf_file, rel.r_offset, target, rel); | |
| 473 | try writer.writeStruct(out_rel); | |
| 474 | } | |
| 475 | } | |
| 476 | ||
| 455 | 477 | for (elf_file.objects.items) |index| { |
| 456 | 478 | const object = elf_file.file(index).?.object; |
| 457 | 479 | |
| ... | ... | @@ -460,7 +482,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { |
| 460 | 482 | for (cie.relocs(elf_file)) |rel| { |
| 461 | 483 | const ref = object.resolveSymbol(rel.r_sym(), elf_file); |
| 462 | 484 | const sym = elf_file.symbol(ref).?; |
| 463 | const out_rel = emitReloc(elf_file, cie, sym, rel); | |
| 485 | const r_offset = cie.address(elf_file) + rel.r_offset - cie.offset; | |
| 486 | const out_rel = emitReloc(elf_file, r_offset, sym, rel); | |
| 464 | 487 | try writer.writeStruct(out_rel); |
| 465 | 488 | } |
| 466 | 489 | } |
| ... | ... | @@ -470,7 +493,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void { |
| 470 | 493 | for (fde.relocs(elf_file)) |rel| { |
| 471 | 494 | const ref = object.resolveSymbol(rel.r_sym(), elf_file); |
| 472 | 495 | const sym = elf_file.symbol(ref).?; |
| 473 | const out_rel = emitReloc(elf_file, fde, sym, rel); | |
| 496 | const r_offset = fde.address(elf_file) + rel.r_offset - fde.offset; | |
| 497 | const out_rel = emitReloc(elf_file, r_offset, sym, rel); | |
| 474 | 498 | try writer.writeStruct(out_rel); |
| 475 | 499 | } |
| 476 | 500 | } |
src/link/Elf/relocatable.zig+80-114| ... | ... | @@ -18,7 +18,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | for (positionals.items) |obj| { |
| 21 | parsePositional(elf_file, obj.path) catch |err| switch (err) { | |
| 21 | parsePositionalStaticLib(elf_file, obj.path) catch |err| switch (err) { | |
| 22 | 22 | error.MalformedObject, |
| 23 | 23 | error.MalformedArchive, |
| 24 | 24 | error.InvalidMachineType, |
| ... | ... | @@ -38,17 +38,12 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 38 | 38 | // First, we flush relocatable object file generated with our backends. |
| 39 | 39 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 40 | 40 | try zig_object.resolveSymbols(elf_file); |
| 41 | elf_file.markEhFrameAtomsDead(); | |
| 41 | 42 | try elf_file.addCommentString(); |
| 42 | 43 | try elf_file.finalizeMergeSections(); |
| 43 | zig_object.claimUnresolvedObject(elf_file); | |
| 44 | zig_object.claimUnresolvedRelocatable(elf_file); | |
| 44 | 45 | |
| 45 | for (elf_file.merge_sections.items) |*msec| { | |
| 46 | if (msec.finalized_subsections.items.len == 0) continue; | |
| 47 | try msec.initOutputSection(elf_file); | |
| 48 | } | |
| 49 | ||
| 50 | try elf_file.initSymtab(); | |
| 51 | try elf_file.initShStrtab(); | |
| 46 | try initSections(elf_file); | |
| 52 | 47 | try elf_file.sortShdrs(); |
| 53 | 48 | try zig_object.addAtomsToRelaSections(elf_file); |
| 54 | 49 | try elf_file.updateMergeSectionSizes(); |
| ... | ... | @@ -208,7 +203,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 208 | 203 | } |
| 209 | 204 | for (elf_file.objects.items) |index| { |
| 210 | 205 | const object = elf_file.file(index).?.object; |
| 211 | try object.addAtomsToOutputSections(elf_file); | |
| 212 | 206 | try object.addAtomsToRelaSections(elf_file); |
| 213 | 207 | } |
| 214 | 208 | try elf_file.updateMergeSectionSizes(); |
| ... | ... | @@ -230,17 +224,17 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 230 | 224 | if (elf_file.base.hasErrors()) return error.FlushFailure; |
| 231 | 225 | } |
| 232 | 226 | |
| 233 | fn parsePositional(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 227 | fn parsePositionalStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 234 | 228 | if (try Object.isObject(path)) { |
| 235 | try parseObject(elf_file, path); | |
| 229 | try parseObjectStaticLib(elf_file, path); | |
| 236 | 230 | } else if (try Archive.isArchive(path)) { |
| 237 | try parseArchive(elf_file, path); | |
| 231 | try parseArchiveStaticLib(elf_file, path); | |
| 238 | 232 | } else return error.UnknownFileType; |
| 239 | 233 | // TODO: should we check for LD script? |
| 240 | 234 | // Actually, should we even unpack an archive? |
| 241 | 235 | } |
| 242 | 236 | |
| 243 | fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 237 | fn parseObjectStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 244 | 238 | const gpa = elf_file.base.comp.gpa; |
| 245 | 239 | const handle = try std.fs.cwd().openFile(path, .{}); |
| 246 | 240 | const fh = try elf_file.addFileHandle(handle); |
| ... | ... | @@ -257,7 +251,7 @@ fn parseObject(elf_file: *Elf, path: []const u8) Elf.ParseError!void { |
| 257 | 251 | try object.parseAr(elf_file); |
| 258 | 252 | } |
| 259 | 253 | |
| 260 | fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 254 | fn parseArchiveStaticLib(elf_file: *Elf, path: []const u8) Elf.ParseError!void { | |
| 261 | 255 | const gpa = elf_file.base.comp.gpa; |
| 262 | 256 | const handle = try std.fs.cwd().openFile(path, .{}); |
| 263 | 257 | const fh = try elf_file.addFileHandle(handle); |
| ... | ... | @@ -281,14 +275,17 @@ fn parseArchive(elf_file: *Elf, path: []const u8) Elf.ParseError!void { |
| 281 | 275 | |
| 282 | 276 | fn claimUnresolved(elf_file: *Elf) void { |
| 283 | 277 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 284 | zig_object.claimUnresolvedObject(elf_file); | |
| 278 | zig_object.claimUnresolvedRelocatable(elf_file); | |
| 285 | 279 | } |
| 286 | 280 | for (elf_file.objects.items) |index| { |
| 287 | elf_file.file(index).?.object.claimUnresolvedObject(elf_file); | |
| 281 | elf_file.file(index).?.object.claimUnresolvedRelocatable(elf_file); | |
| 288 | 282 | } |
| 289 | 283 | } |
| 290 | 284 | |
| 291 | 285 | fn initSections(elf_file: *Elf) !void { |
| 286 | if (elf_file.zigObjectPtr()) |zo| { | |
| 287 | try zo.initRelaSections(elf_file); | |
| 288 | } | |
| 292 | 289 | for (elf_file.objects.items) |index| { |
| 293 | 290 | const object = elf_file.file(index).?.object; |
| 294 | 291 | try object.initOutputSections(elf_file); |
| ... | ... | @@ -300,12 +297,17 @@ fn initSections(elf_file: *Elf) !void { |
| 300 | 297 | try msec.initOutputSection(elf_file); |
| 301 | 298 | } |
| 302 | 299 | |
| 303 | const needs_eh_frame = for (elf_file.objects.items) |index| { | |
| 304 | if (elf_file.file(index).?.object.cies.items.len > 0) break true; | |
| 305 | } else false; | |
| 300 | const needs_eh_frame = blk: { | |
| 301 | if (elf_file.zigObjectPtr()) |zo| | |
| 302 | if (zo.eh_frame_index != null) break :blk true; | |
| 303 | break :blk for (elf_file.objects.items) |index| { | |
| 304 | if (elf_file.file(index).?.object.cies.items.len > 0) break true; | |
| 305 | } else false; | |
| 306 | }; | |
| 306 | 307 | if (needs_eh_frame) { |
| 307 | 308 | if (elf_file.eh_frame_section_index == null) { |
| 308 | elf_file.eh_frame_section_index = try elf_file.addSection(.{ | |
| 309 | elf_file.eh_frame_section_index = elf_file.sectionByName(".eh_frame") orelse | |
| 310 | try elf_file.addSection(.{ | |
| 309 | 311 | .name = try elf_file.insertShString(".eh_frame"), |
| 310 | 312 | .type = if (elf_file.getTarget().cpu.arch == .x86_64) |
| 311 | 313 | elf.SHT_X86_64_UNWIND |
| ... | ... | @@ -316,7 +318,8 @@ fn initSections(elf_file: *Elf) !void { |
| 316 | 318 | .offset = std.math.maxInt(u64), |
| 317 | 319 | }); |
| 318 | 320 | } |
| 319 | elf_file.eh_frame_rela_section_index = try elf_file.addRelaShdr( | |
| 321 | elf_file.eh_frame_rela_section_index = elf_file.sectionByName(".rela.eh_frame") orelse | |
| 322 | try elf_file.addRelaShdr( | |
| 320 | 323 | try elf_file.insertShString(".rela.eh_frame"), |
| 321 | 324 | elf_file.eh_frame_section_index.?, |
| 322 | 325 | ); |
| ... | ... | @@ -351,36 +354,28 @@ fn initComdatGroups(elf_file: *Elf) !void { |
| 351 | 354 | |
| 352 | 355 | fn updateSectionSizes(elf_file: *Elf) !void { |
| 353 | 356 | const slice = elf_file.sections.slice(); |
| 357 | for (slice.items(.atom_list_2)) |*atom_list| { | |
| 358 | if (atom_list.atoms.items.len == 0) continue; | |
| 359 | atom_list.updateSize(elf_file); | |
| 360 | try atom_list.allocate(elf_file); | |
| 361 | } | |
| 362 | ||
| 354 | 363 | for (slice.items(.shdr), 0..) |*shdr, shndx| { |
| 355 | 364 | const atom_list = slice.items(.atom_list)[shndx]; |
| 356 | if (shdr.sh_type != elf.SHT_RELA) { | |
| 357 | for (atom_list.items) |ref| { | |
| 358 | const atom_ptr = elf_file.atom(ref) orelse continue; | |
| 359 | if (!atom_ptr.alive) continue; | |
| 360 | const offset = atom_ptr.alignment.forward(shdr.sh_size); | |
| 361 | const padding = offset - shdr.sh_size; | |
| 362 | atom_ptr.value = @intCast(offset); | |
| 363 | shdr.sh_size += padding + atom_ptr.size; | |
| 364 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits() orelse 1); | |
| 365 | } | |
| 366 | } else { | |
| 367 | for (atom_list.items) |ref| { | |
| 368 | const atom_ptr = elf_file.atom(ref) orelse continue; | |
| 369 | if (!atom_ptr.alive) continue; | |
| 370 | const relocs = atom_ptr.relocs(elf_file); | |
| 371 | shdr.sh_size += shdr.sh_entsize * relocs.len; | |
| 372 | } | |
| 373 | ||
| 374 | if (shdr.sh_size == 0) shdr.sh_offset = 0; | |
| 365 | if (shdr.sh_type != elf.SHT_RELA) continue; | |
| 366 | if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue; | |
| 367 | for (atom_list.items) |ref| { | |
| 368 | const atom_ptr = elf_file.atom(ref) orelse continue; | |
| 369 | if (!atom_ptr.alive) continue; | |
| 370 | const relocs = atom_ptr.relocs(elf_file); | |
| 371 | shdr.sh_size += shdr.sh_entsize * relocs.len; | |
| 375 | 372 | } |
| 373 | ||
| 374 | if (shdr.sh_size == 0) shdr.sh_offset = 0; | |
| 376 | 375 | } |
| 377 | 376 | |
| 378 | 377 | if (elf_file.eh_frame_section_index) |index| { |
| 379 | slice.items(.shdr)[index].sh_size = existing_size: { | |
| 380 | const zo = elf_file.zigObjectPtr() orelse break :existing_size 0; | |
| 381 | const sym = zo.symbol(zo.eh_frame_index orelse break :existing_size 0); | |
| 382 | break :existing_size sym.atom(elf_file).?.size; | |
| 383 | } + try eh_frame.calcEhFrameSize(elf_file); | |
| 378 | slice.items(.shdr)[index].sh_size = try eh_frame.calcEhFrameSize(elf_file); | |
| 384 | 379 | } |
| 385 | 380 | if (elf_file.eh_frame_rela_section_index) |index| { |
| 386 | 381 | const shdr = &slice.items(.shdr)[index]; |
| ... | ... | @@ -405,7 +400,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void { |
| 405 | 400 | |
| 406 | 401 | /// Allocates alloc sections when merging relocatable objects files together. |
| 407 | 402 | fn allocateAllocSections(elf_file: *Elf) !void { |
| 408 | for (elf_file.sections.items(.shdr)) |*shdr| { | |
| 403 | for (elf_file.sections.items(.shdr), 0..) |*shdr, shndx| { | |
| 409 | 404 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 410 | 405 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 411 | 406 | if (shdr.sh_type == elf.SHT_NOBITS) { |
| ... | ... | @@ -416,6 +411,34 @@ fn allocateAllocSections(elf_file: *Elf) !void { |
| 416 | 411 | if (needed_size > elf_file.allocatedSize(shdr.sh_offset)) { |
| 417 | 412 | shdr.sh_size = 0; |
| 418 | 413 | const new_offset = try elf_file.findFreeSpace(needed_size, shdr.sh_addralign); |
| 414 | ||
| 415 | if (elf_file.zigObjectPtr()) |zo| blk: { | |
| 416 | const existing_size = for ([_]?Symbol.Index{ | |
| 417 | zo.text_index, | |
| 418 | zo.rodata_index, | |
| 419 | zo.data_relro_index, | |
| 420 | zo.data_index, | |
| 421 | zo.tdata_index, | |
| 422 | zo.eh_frame_index, | |
| 423 | }) |maybe_sym_index| { | |
| 424 | const sect_sym_index = maybe_sym_index orelse continue; | |
| 425 | const sect_atom_ptr = zo.symbol(sect_sym_index).atom(elf_file).?; | |
| 426 | if (sect_atom_ptr.output_section_index == shndx) break sect_atom_ptr.size; | |
| 427 | } else break :blk; | |
| 428 | log.debug("moving {s} from 0x{x} to 0x{x}", .{ | |
| 429 | elf_file.getShString(shdr.sh_name), | |
| 430 | shdr.sh_offset, | |
| 431 | new_offset, | |
| 432 | }); | |
| 433 | const amt = try elf_file.base.file.?.copyRangeAll( | |
| 434 | shdr.sh_offset, | |
| 435 | elf_file.base.file.?, | |
| 436 | new_offset, | |
| 437 | existing_size, | |
| 438 | ); | |
| 439 | if (amt != existing_size) return error.InputOutput; | |
| 440 | } | |
| 441 | ||
| 419 | 442 | shdr.sh_offset = new_offset; |
| 420 | 443 | shdr.sh_size = needed_size; |
| 421 | 444 | } |
| ... | ... | @@ -424,73 +447,15 @@ fn allocateAllocSections(elf_file: *Elf) !void { |
| 424 | 447 | |
| 425 | 448 | fn writeAtoms(elf_file: *Elf) !void { |
| 426 | 449 | const gpa = elf_file.base.comp.gpa; |
| 427 | const slice = elf_file.sections.slice(); | |
| 428 | ||
| 429 | // TODO iterate over `output_sections` directly | |
| 430 | for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { | |
| 431 | if (shdr.sh_type == elf.SHT_NULL) continue; | |
| 432 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | |
| 433 | if (shdr.sh_type == elf.SHT_RELA) continue; | |
| 434 | if (atom_list.items.len == 0) continue; | |
| 435 | ||
| 436 | log.debug("writing atoms in '{s}' section", .{elf_file.getShString(shdr.sh_name)}); | |
| 437 | ||
| 438 | // TODO really, really handle debug section separately | |
| 439 | const base_offset = if (elf_file.isDebugSection(@intCast(shndx))) blk: { | |
| 440 | const zo = elf_file.zigObjectPtr().?; | |
| 441 | break :blk for ([_]Symbol.Index{ | |
| 442 | zo.debug_info_index.?, | |
| 443 | zo.debug_abbrev_index.?, | |
| 444 | zo.debug_aranges_index.?, | |
| 445 | zo.debug_str_index.?, | |
| 446 | zo.debug_line_index.?, | |
| 447 | zo.debug_line_str_index.?, | |
| 448 | zo.debug_loclists_index.?, | |
| 449 | zo.debug_rnglists_index.?, | |
| 450 | }) |sym_index| { | |
| 451 | const sym = zo.symbol(sym_index); | |
| 452 | const atom_ptr = sym.atom(elf_file).?; | |
| 453 | if (atom_ptr.output_section_index == shndx) break atom_ptr.size; | |
| 454 | } else 0; | |
| 455 | } else 0; | |
| 456 | const sh_offset = shdr.sh_offset + base_offset; | |
| 457 | const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; | |
| 458 | ||
| 459 | const buffer = try gpa.alloc(u8, sh_size); | |
| 460 | defer gpa.free(buffer); | |
| 461 | const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and | |
| 462 | shdr.sh_flags & elf.SHF_EXECINSTR != 0) | |
| 463 | 0xcc // int3 | |
| 464 | else | |
| 465 | 0; | |
| 466 | @memset(buffer, padding_byte); | |
| 467 | ||
| 468 | for (atom_list.items) |ref| { | |
| 469 | const atom_ptr = elf_file.atom(ref).?; | |
| 470 | assert(atom_ptr.alive); | |
| 471 | ||
| 472 | const offset = math.cast(usize, atom_ptr.value - @as(i64, @intCast(shdr.sh_addr - base_offset))) orelse | |
| 473 | return error.Overflow; | |
| 474 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; | |
| 475 | 450 | |
| 476 | log.debug("writing atom({}) from 0x{x} to 0x{x}", .{ | |
| 477 | ref, | |
| 478 | sh_offset + offset, | |
| 479 | sh_offset + offset + size, | |
| 480 | }); | |
| 481 | ||
| 482 | // TODO decompress directly into provided buffer | |
| 483 | const out_code = buffer[offset..][0..size]; | |
| 484 | const in_code = switch (atom_ptr.file(elf_file).?) { | |
| 485 | .object => |x| try x.codeDecompressAlloc(elf_file, ref.index), | |
| 486 | .zig_object => |x| try x.codeAlloc(elf_file, ref.index), | |
| 487 | else => unreachable, | |
| 488 | }; | |
| 489 | defer gpa.free(in_code); | |
| 490 | @memcpy(out_code, in_code); | |
| 491 | } | |
| 451 | var buffer = std.ArrayList(u8).init(gpa); | |
| 452 | defer buffer.deinit(); | |
| 492 | 453 | |
| 493 | try elf_file.base.file.?.pwriteAll(buffer, sh_offset); | |
| 454 | const slice = elf_file.sections.slice(); | |
| 455 | for (slice.items(.shdr), slice.items(.atom_list_2)) |shdr, atom_list| { | |
| 456 | if (shdr.sh_type == elf.SHT_NOBITS) continue; | |
| 457 | if (atom_list.atoms.items.len == 0) continue; | |
| 458 | try atom_list.writeRelocatable(&buffer, elf_file); | |
| 494 | 459 | } |
| 495 | 460 | } |
| 496 | 461 | |
| ... | ... | @@ -498,9 +463,10 @@ fn writeSyntheticSections(elf_file: *Elf) !void { |
| 498 | 463 | const gpa = elf_file.base.comp.gpa; |
| 499 | 464 | const slice = elf_file.sections.slice(); |
| 500 | 465 | |
| 501 | for (slice.items(.shdr), slice.items(.atom_list)) |shdr, atom_list| { | |
| 466 | for (slice.items(.shdr), slice.items(.atom_list), 0..) |shdr, atom_list, shndx| { | |
| 502 | 467 | if (shdr.sh_type != elf.SHT_RELA) continue; |
| 503 | 468 | if (atom_list.items.len == 0) continue; |
| 469 | if (@as(u32, @intCast(shndx)) == elf_file.eh_frame_section_index) continue; | |
| 504 | 470 | |
| 505 | 471 | const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse |
| 506 | 472 | return error.Overflow; |
| ... | ... | @@ -542,7 +508,7 @@ fn writeSyntheticSections(elf_file: *Elf) !void { |
| 542 | 508 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 543 | 509 | var buffer = try std.ArrayList(u8).initCapacity(gpa, @intCast(sh_size - existing_size)); |
| 544 | 510 | defer buffer.deinit(); |
| 545 | try eh_frame.writeEhFrameObject(elf_file, buffer.writer()); | |
| 511 | try eh_frame.writeEhFrameRelocatable(elf_file, buffer.writer()); | |
| 546 | 512 | log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ |
| 547 | 513 | shdr.sh_offset + existing_size, |
| 548 | 514 | shdr.sh_offset + sh_size, |
test/link/elf.zig+2| ... | ... | @@ -55,6 +55,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 55 | 55 | |
| 56 | 56 | // Exercise linker in ar mode |
| 57 | 57 | elf_step.dependOn(testEmitStaticLib(b, .{ .target = musl_target })); |
| 58 | elf_step.dependOn(testEmitStaticLibZig(b, .{ .target = musl_target })); | |
| 58 | 59 | |
| 59 | 60 | // Exercise linker with LLVM backend |
| 60 | 61 | // musl tests |
| ... | ... | @@ -66,6 +67,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { |
| 66 | 67 | elf_step.dependOn(testEmptyObject(b, .{ .target = musl_target })); |
| 67 | 68 | elf_step.dependOn(testEntryPoint(b, .{ .target = musl_target })); |
| 68 | 69 | elf_step.dependOn(testGcSections(b, .{ .target = musl_target })); |
| 70 | elf_step.dependOn(testGcSectionsZig(b, .{ .target = musl_target })); | |
| 69 | 71 | elf_step.dependOn(testImageBase(b, .{ .target = musl_target })); |
| 70 | 72 | elf_step.dependOn(testInitArrayOrder(b, .{ .target = musl_target })); |
| 71 | 73 | elf_step.dependOn(testLargeAlignmentExe(b, .{ .target = musl_target })); |