| ... | ... | @@ -18,12 +18,13 @@ shared_objects: std.ArrayListUnmanaged(File.Index) = .{}, |
| 18 | 18 | /// Same order as in the file. |
| 19 | 19 | shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{}, |
| 20 | 20 | /// Given index to a section, pulls index of containing phdr if any. |
| 21 | | phdr_to_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{}, |
| 21 | phdr_to_shdr_table: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 22 | 22 | /// File offset into the shdr table. |
| 23 | 23 | shdr_table_offset: ?u64 = null, |
| 24 | 24 | /// Table of lists of atoms per output section. |
| 25 | 25 | /// This table is not used to track incrementally generated atoms. |
| 26 | | output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{}, |
| 26 | output_sections: std.AutoArrayHashMapUnmanaged(u32, std.ArrayListUnmanaged(Atom.Index)) = .{}, |
| 27 | output_rela_sections: std.AutoArrayHashMapUnmanaged(u32, RelaSection) = .{}, |
| 27 | 28 | |
| 28 | 29 | /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write. |
| 29 | 30 | /// Same order as in the file. |
| ... | ... | @@ -101,15 +102,15 @@ copy_rel: CopyRelSection = .{}, |
| 101 | 102 | rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{}, |
| 102 | 103 | /// .got.zig section |
| 103 | 104 | zig_got: ZigGotSection = .{}, |
| 105 | /// SHT_GROUP sections |
| 106 | /// Applies only to a relocatable. |
| 107 | comdat_group_sections: std.ArrayListUnmanaged(ComdatGroupSection) = .{}, |
| 104 | 108 | |
| 105 | 109 | /// Tracked section headers with incremental updates to Zig object. |
| 106 | 110 | /// .rela.* sections are only used when emitting a relocatable object file. |
| 107 | 111 | zig_text_section_index: ?u16 = null, |
| 108 | | zig_text_rela_section_index: ?u16 = null, |
| 109 | 112 | zig_data_rel_ro_section_index: ?u16 = null, |
| 110 | | zig_data_rel_ro_rela_section_index: ?u16 = null, |
| 111 | 113 | zig_data_section_index: ?u16 = null, |
| 112 | | zig_data_rela_section_index: ?u16 = null, |
| 113 | 114 | zig_bss_section_index: ?u16 = null, |
| 114 | 115 | zig_got_section_index: ?u16 = null, |
| 115 | 116 | |
| ... | ... | @@ -124,6 +125,7 @@ dynamic_section_index: ?u16 = null, |
| 124 | 125 | dynstrtab_section_index: ?u16 = null, |
| 125 | 126 | dynsymtab_section_index: ?u16 = null, |
| 126 | 127 | eh_frame_section_index: ?u16 = null, |
| 128 | eh_frame_rela_section_index: ?u16 = null, |
| 127 | 129 | eh_frame_hdr_section_index: ?u16 = null, |
| 128 | 130 | hash_section_index: ?u16 = null, |
| 129 | 131 | gnu_hash_section_index: ?u16 = null, |
| ... | ... | @@ -216,10 +218,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 216 | 218 | sub_path, options.target.ofmt.fileExt(options.target.cpu.arch), |
| 217 | 219 | }); |
| 218 | 220 | } |
| 219 | | if (is_obj) { |
| 220 | | // TODO until we implement -r option, we don't want to open a file at this stage. |
| 221 | | return self; |
| 222 | | } |
| 223 | 221 | } |
| 224 | 222 | errdefer if (self.base.intermediary_basename) |path| allocator.free(path); |
| 225 | 223 | |
| ... | ... | @@ -361,6 +359,10 @@ pub fn deinit(self: *Elf) void { |
| 361 | 359 | list.deinit(gpa); |
| 362 | 360 | } |
| 363 | 361 | self.output_sections.deinit(gpa); |
| 362 | for (self.output_rela_sections.values()) |*sec| { |
| 363 | sec.atom_list.deinit(gpa); |
| 364 | } |
| 365 | self.output_rela_sections.deinit(gpa); |
| 364 | 366 | self.shstrtab.deinit(gpa); |
| 365 | 367 | self.symtab.deinit(gpa); |
| 366 | 368 | self.strtab.deinit(gpa); |
| ... | ... | @@ -395,6 +397,7 @@ pub fn deinit(self: *Elf) void { |
| 395 | 397 | self.rela_dyn.deinit(gpa); |
| 396 | 398 | self.rela_plt.deinit(gpa); |
| 397 | 399 | self.zig_got.deinit(gpa); |
| 400 | self.comdat_group_sections.deinit(gpa); |
| 398 | 401 | } |
| 399 | 402 | |
| 400 | 403 | pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { |
| ... | ... | @@ -601,11 +604,10 @@ pub fn initMetadata(self: *Elf) !void { |
| 601 | 604 | const shdr = &self.shdrs.items[self.zig_text_section_index.?]; |
| 602 | 605 | fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index); |
| 603 | 606 | if (self.isRelocatable()) { |
| 604 | | try zig_object.addSectionSymbol(self.zig_text_section_index.?, self); |
| 605 | | self.zig_text_rela_section_index = try self.addRelaShdr( |
| 606 | | ".rela.text.zig", |
| 607 | | self.zig_text_section_index.?, |
| 608 | | ); |
| 607 | const rela_shndx = try self.addRelaShdr(".rela.text.zig", self.zig_text_section_index.?); |
| 608 | try self.output_rela_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{ |
| 609 | .shndx = rela_shndx, |
| 610 | }); |
| 609 | 611 | } else { |
| 610 | 612 | try self.phdr_to_shdr_table.putNoClobber( |
| 611 | 613 | gpa, |
| ... | ... | @@ -613,6 +615,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 613 | 615 | self.phdr_zig_load_re_index.?, |
| 614 | 616 | ); |
| 615 | 617 | } |
| 618 | try self.output_sections.putNoClobber(gpa, self.zig_text_section_index.?, .{}); |
| 616 | 619 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{}); |
| 617 | 620 | } |
| 618 | 621 | |
| ... | ... | @@ -642,17 +645,19 @@ pub fn initMetadata(self: *Elf) !void { |
| 642 | 645 | .name = ".data.rel.ro.zig", |
| 643 | 646 | .type = elf.SHT_PROGBITS, |
| 644 | 647 | .addralign = 1, |
| 645 | | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro |
| 648 | .flags = elf.SHF_ALLOC | elf.SHF_WRITE, |
| 646 | 649 | .offset = std.math.maxInt(u64), |
| 647 | 650 | }); |
| 648 | 651 | const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?]; |
| 649 | 652 | fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index); |
| 650 | 653 | if (self.isRelocatable()) { |
| 651 | | try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self); |
| 652 | | self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr( |
| 654 | const rela_shndx = try self.addRelaShdr( |
| 653 | 655 | ".rela.data.rel.ro.zig", |
| 654 | 656 | self.zig_data_rel_ro_section_index.?, |
| 655 | 657 | ); |
| 658 | try self.output_rela_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{ |
| 659 | .shndx = rela_shndx, |
| 660 | }); |
| 656 | 661 | } else { |
| 657 | 662 | try self.phdr_to_shdr_table.putNoClobber( |
| 658 | 663 | gpa, |
| ... | ... | @@ -660,6 +665,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 660 | 665 | self.phdr_zig_load_ro_index.?, |
| 661 | 666 | ); |
| 662 | 667 | } |
| 668 | try self.output_sections.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{}); |
| 663 | 669 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{}); |
| 664 | 670 | } |
| 665 | 671 | |
| ... | ... | @@ -674,11 +680,13 @@ pub fn initMetadata(self: *Elf) !void { |
| 674 | 680 | const shdr = &self.shdrs.items[self.zig_data_section_index.?]; |
| 675 | 681 | fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index); |
| 676 | 682 | if (self.isRelocatable()) { |
| 677 | | try zig_object.addSectionSymbol(self.zig_data_section_index.?, self); |
| 678 | | self.zig_data_rela_section_index = try self.addRelaShdr( |
| 683 | const rela_shndx = try self.addRelaShdr( |
| 679 | 684 | ".rela.data.zig", |
| 680 | 685 | self.zig_data_section_index.?, |
| 681 | 686 | ); |
| 687 | try self.output_rela_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{ |
| 688 | .shndx = rela_shndx, |
| 689 | }); |
| 682 | 690 | } else { |
| 683 | 691 | try self.phdr_to_shdr_table.putNoClobber( |
| 684 | 692 | gpa, |
| ... | ... | @@ -686,6 +694,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 686 | 694 | self.phdr_zig_load_rw_index.?, |
| 687 | 695 | ); |
| 688 | 696 | } |
| 697 | try self.output_sections.putNoClobber(gpa, self.zig_data_section_index.?, .{}); |
| 689 | 698 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{}); |
| 690 | 699 | } |
| 691 | 700 | |
| ... | ... | @@ -704,9 +713,9 @@ pub fn initMetadata(self: *Elf) !void { |
| 704 | 713 | shdr.sh_size = phdr.p_memsz; |
| 705 | 714 | try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx); |
| 706 | 715 | } else { |
| 707 | | try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self); |
| 708 | 716 | shdr.sh_size = 1024; |
| 709 | 717 | } |
| 718 | try self.output_sections.putNoClobber(gpa, self.zig_bss_section_index.?, .{}); |
| 710 | 719 | try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{}); |
| 711 | 720 | } |
| 712 | 721 | |
| ... | ... | @@ -728,6 +737,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 728 | 737 | shdr.sh_offset = off; |
| 729 | 738 | shdr.sh_size = size; |
| 730 | 739 | zig_object.debug_strtab_dirty = true; |
| 740 | try self.output_sections.putNoClobber(gpa, self.debug_str_section_index.?, .{}); |
| 731 | 741 | } |
| 732 | 742 | |
| 733 | 743 | if (self.debug_info_section_index == null) { |
| ... | ... | @@ -743,6 +753,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 743 | 753 | shdr.sh_offset = off; |
| 744 | 754 | shdr.sh_size = size; |
| 745 | 755 | zig_object.debug_info_header_dirty = true; |
| 756 | try self.output_sections.putNoClobber(gpa, self.debug_info_section_index.?, .{}); |
| 746 | 757 | } |
| 747 | 758 | |
| 748 | 759 | if (self.debug_abbrev_section_index == null) { |
| ... | ... | @@ -758,6 +769,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 758 | 769 | shdr.sh_offset = off; |
| 759 | 770 | shdr.sh_size = size; |
| 760 | 771 | zig_object.debug_abbrev_section_dirty = true; |
| 772 | try self.output_sections.putNoClobber(gpa, self.debug_abbrev_section_index.?, .{}); |
| 761 | 773 | } |
| 762 | 774 | |
| 763 | 775 | if (self.debug_aranges_section_index == null) { |
| ... | ... | @@ -773,6 +785,7 @@ pub fn initMetadata(self: *Elf) !void { |
| 773 | 785 | shdr.sh_offset = off; |
| 774 | 786 | shdr.sh_size = size; |
| 775 | 787 | zig_object.debug_aranges_section_dirty = true; |
| 788 | try self.output_sections.putNoClobber(gpa, self.debug_aranges_section_index.?, .{}); |
| 776 | 789 | } |
| 777 | 790 | |
| 778 | 791 | if (self.debug_line_section_index == null) { |
| ... | ... | @@ -788,8 +801,17 @@ pub fn initMetadata(self: *Elf) !void { |
| 788 | 801 | shdr.sh_offset = off; |
| 789 | 802 | shdr.sh_size = size; |
| 790 | 803 | zig_object.debug_line_header_dirty = true; |
| 804 | try self.output_sections.putNoClobber(gpa, self.debug_line_section_index.?, .{}); |
| 791 | 805 | } |
| 792 | 806 | } |
| 807 | |
| 808 | // We need to find current max assumed file offset, and actually write to file to make it a reality. |
| 809 | var end_pos: u64 = 0; |
| 810 | for (self.shdrs.items) |shdr| { |
| 811 | if (shdr.sh_offset == std.math.maxInt(u64)) continue; |
| 812 | end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size); |
| 813 | } |
| 814 | try self.base.file.?.pwriteAll(&[1]u8{0}, end_pos); |
| 793 | 815 | } |
| 794 | 816 | |
| 795 | 817 | pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void { |
| ... | ... | @@ -942,30 +964,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 942 | 964 | } else null; |
| 943 | 965 | const gc_sections = self.base.options.gc_sections orelse false; |
| 944 | 966 | |
| 945 | | if (self.isObject() and self.zig_object_index == null) { |
| 946 | | // TODO this will become -r route I guess. For now, just copy the object file. |
| 947 | | const the_object_path = blk: { |
| 948 | | if (self.base.options.objects.len != 0) { |
| 949 | | break :blk self.base.options.objects[0].path; |
| 950 | | } |
| 951 | | |
| 952 | | if (comp.c_object_table.count() != 0) |
| 953 | | break :blk comp.c_object_table.keys()[0].status.success.object_path; |
| 954 | | |
| 955 | | if (module_obj_path) |p| |
| 956 | | break :blk p; |
| 957 | | |
| 958 | | // TODO I think this is unreachable. Audit this situation when solving the above TODO |
| 959 | | // regarding eliding redundant object -> object transformations. |
| 960 | | return error.NoObjectsToLink; |
| 961 | | }; |
| 962 | | // This can happen when using --enable-cache and using the stage1 backend. In this case |
| 963 | | // we can skip the file copy. |
| 964 | | if (!mem.eql(u8, the_object_path, full_out_path)) { |
| 965 | | try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{}); |
| 966 | | } |
| 967 | | return; |
| 968 | | } |
| 967 | // --verbose-link |
| 968 | if (self.base.options.verbose_link) try self.dumpArgv(comp); |
| 969 | 969 | |
| 970 | 970 | var csu = try CsuObjects.init(arena, self.base.options, comp); |
| 971 | 971 | const compiler_rt_path: ?[]const u8 = blk: { |
| ... | ... | @@ -974,247 +974,9 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 974 | 974 | break :blk null; |
| 975 | 975 | }; |
| 976 | 976 | |
| 977 | | // --verbose-link |
| 978 | | if (self.base.options.verbose_link) { |
| 979 | | var argv = std.ArrayList([]const u8).init(arena); |
| 980 | | |
| 981 | | try argv.append("zig"); |
| 982 | | try argv.append("ld"); |
| 983 | | |
| 984 | | try argv.append("-o"); |
| 985 | | try argv.append(full_out_path); |
| 986 | | |
| 987 | | if (self.base.options.entry) |entry| { |
| 988 | | try argv.append("--entry"); |
| 989 | | try argv.append(entry); |
| 990 | | } |
| 991 | | |
| 992 | | if (self.base.options.dynamic_linker) |path| { |
| 993 | | try argv.append("-dynamic-linker"); |
| 994 | | try argv.append(path); |
| 995 | | } |
| 996 | | |
| 997 | | if (self.base.options.soname) |name| { |
| 998 | | try argv.append("-soname"); |
| 999 | | try argv.append(name); |
| 1000 | | } |
| 1001 | | |
| 1002 | | for (self.base.options.rpath_list) |rpath| { |
| 1003 | | try argv.append("-rpath"); |
| 1004 | | try argv.append(rpath); |
| 1005 | | } |
| 1006 | | |
| 1007 | | if (self.base.options.each_lib_rpath) { |
| 1008 | | for (self.base.options.lib_dirs) |lib_dir_path| { |
| 1009 | | try argv.append("-rpath"); |
| 1010 | | try argv.append(lib_dir_path); |
| 1011 | | } |
| 1012 | | for (self.base.options.objects) |obj| { |
| 1013 | | if (Compilation.classifyFileExt(obj.path) == .shared_library) { |
| 1014 | | const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; |
| 1015 | | if (obj.loption) continue; |
| 1016 | | |
| 1017 | | try argv.append("-rpath"); |
| 1018 | | try argv.append(lib_dir_path); |
| 1019 | | } |
| 1020 | | } |
| 1021 | | } |
| 1022 | | |
| 1023 | | if (self.base.options.stack_size_override) |ss| { |
| 1024 | | try argv.append("-z"); |
| 1025 | | try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss})); |
| 1026 | | } |
| 1027 | | |
| 1028 | | if (self.base.options.image_base_override) |image_base| { |
| 1029 | | try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base})); |
| 1030 | | } |
| 1031 | | |
| 1032 | | if (gc_sections) { |
| 1033 | | try argv.append("--gc-sections"); |
| 1034 | | } |
| 1035 | | |
| 1036 | | if (self.base.options.print_gc_sections) { |
| 1037 | | try argv.append("--print-gc-sections"); |
| 1038 | | } |
| 1039 | | |
| 1040 | | if (self.base.options.eh_frame_hdr) { |
| 1041 | | try argv.append("--eh-frame-hdr"); |
| 1042 | | } |
| 1043 | | |
| 1044 | | if (self.base.options.rdynamic) { |
| 1045 | | try argv.append("--export-dynamic"); |
| 1046 | | } |
| 1047 | | |
| 1048 | | if (self.base.options.strip) { |
| 1049 | | try argv.append("-s"); |
| 1050 | | } |
| 1051 | | |
| 1052 | | if (self.base.options.z_notext) { |
| 1053 | | try argv.append("-z"); |
| 1054 | | try argv.append("notext"); |
| 1055 | | } |
| 1056 | | |
| 1057 | | if (self.base.options.z_nocopyreloc) { |
| 1058 | | try argv.append("-z"); |
| 1059 | | try argv.append("nocopyreloc"); |
| 1060 | | } |
| 1061 | | |
| 1062 | | if (self.base.options.z_now) { |
| 1063 | | try argv.append("-z"); |
| 1064 | | try argv.append("now"); |
| 1065 | | } |
| 1066 | | |
| 1067 | | if (self.isStatic()) { |
| 1068 | | try argv.append("-static"); |
| 1069 | | } else if (self.isDynLib()) { |
| 1070 | | try argv.append("-shared"); |
| 1071 | | } |
| 1072 | | |
| 1073 | | if (self.base.options.pie and self.isExe()) { |
| 1074 | | try argv.append("-pie"); |
| 1075 | | } |
| 1076 | | |
| 1077 | | // csu prelude |
| 1078 | | if (csu.crt0) |v| try argv.append(v); |
| 1079 | | if (csu.crti) |v| try argv.append(v); |
| 1080 | | if (csu.crtbegin) |v| try argv.append(v); |
| 1081 | | |
| 1082 | | for (self.base.options.lib_dirs) |lib_dir| { |
| 1083 | | try argv.append("-L"); |
| 1084 | | try argv.append(lib_dir); |
| 1085 | | } |
| 1086 | | |
| 1087 | | if (self.base.options.link_libc) { |
| 1088 | | if (self.base.options.libc_installation) |libc_installation| { |
| 1089 | | try argv.append("-L"); |
| 1090 | | try argv.append(libc_installation.crt_dir.?); |
| 1091 | | } |
| 1092 | | } |
| 1093 | | |
| 1094 | | var whole_archive = false; |
| 1095 | | for (self.base.options.objects) |obj| { |
| 1096 | | if (obj.must_link and !whole_archive) { |
| 1097 | | try argv.append("-whole-archive"); |
| 1098 | | whole_archive = true; |
| 1099 | | } else if (!obj.must_link and whole_archive) { |
| 1100 | | try argv.append("-no-whole-archive"); |
| 1101 | | whole_archive = false; |
| 1102 | | } |
| 1103 | | |
| 1104 | | if (obj.loption) { |
| 1105 | | assert(obj.path[0] == ':'); |
| 1106 | | try argv.append("-l"); |
| 1107 | | } |
| 1108 | | try argv.append(obj.path); |
| 1109 | | } |
| 1110 | | if (whole_archive) { |
| 1111 | | try argv.append("-no-whole-archive"); |
| 1112 | | whole_archive = false; |
| 1113 | | } |
| 1114 | | |
| 1115 | | for (comp.c_object_table.keys()) |key| { |
| 1116 | | try argv.append(key.status.success.object_path); |
| 1117 | | } |
| 1118 | | |
| 1119 | | if (module_obj_path) |p| { |
| 1120 | | try argv.append(p); |
| 1121 | | } |
| 1122 | | |
| 1123 | | // TSAN |
| 1124 | | if (self.base.options.tsan) { |
| 1125 | | try argv.append(comp.tsan_static_lib.?.full_object_path); |
| 1126 | | } |
| 1127 | | |
| 1128 | | // libc |
| 1129 | | if (!self.base.options.skip_linker_dependencies and |
| 1130 | | !self.base.options.link_libc) |
| 1131 | | { |
| 1132 | | if (comp.libc_static_lib) |lib| { |
| 1133 | | try argv.append(lib.full_object_path); |
| 1134 | | } |
| 1135 | | } |
| 1136 | | |
| 1137 | | // stack-protector. |
| 1138 | | // Related: https://github.com/ziglang/zig/issues/7265 |
| 1139 | | if (comp.libssp_static_lib) |ssp| { |
| 1140 | | try argv.append(ssp.full_object_path); |
| 1141 | | } |
| 1142 | | |
| 1143 | | // Shared libraries. |
| 1144 | | // Worst-case, we need an --as-needed argument for every lib, as well |
| 1145 | | // as one before and one after. |
| 1146 | | try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2); |
| 1147 | | argv.appendAssumeCapacity("--as-needed"); |
| 1148 | | var as_needed = true; |
| 1149 | | |
| 1150 | | for (self.base.options.system_libs.values()) |lib_info| { |
| 1151 | | const lib_as_needed = !lib_info.needed; |
| 1152 | | switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { |
| 1153 | | 0b00, 0b11 => {}, |
| 1154 | | 0b01 => { |
| 1155 | | argv.appendAssumeCapacity("--no-as-needed"); |
| 1156 | | as_needed = false; |
| 1157 | | }, |
| 1158 | | 0b10 => { |
| 1159 | | argv.appendAssumeCapacity("--as-needed"); |
| 1160 | | as_needed = true; |
| 1161 | | }, |
| 1162 | | } |
| 1163 | | argv.appendAssumeCapacity(lib_info.path.?); |
| 1164 | | } |
| 1165 | | |
| 1166 | | if (!as_needed) { |
| 1167 | | argv.appendAssumeCapacity("--as-needed"); |
| 1168 | | as_needed = true; |
| 1169 | | } |
| 1170 | | |
| 1171 | | // libc++ dep |
| 1172 | | if (self.base.options.link_libcpp) { |
| 1173 | | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); |
| 1174 | | try argv.append(comp.libcxx_static_lib.?.full_object_path); |
| 1175 | | } |
| 1176 | | |
| 1177 | | // libunwind dep |
| 1178 | | if (self.base.options.link_libunwind) { |
| 1179 | | try argv.append(comp.libunwind_static_lib.?.full_object_path); |
| 1180 | | } |
| 1181 | | |
| 1182 | | // libc dep |
| 1183 | | if (self.base.options.link_libc) { |
| 1184 | | if (self.base.options.libc_installation != null) { |
| 1185 | | const needs_grouping = self.base.options.link_mode == .Static; |
| 1186 | | if (needs_grouping) try argv.append("--start-group"); |
| 1187 | | try argv.appendSlice(target_util.libcFullLinkFlags(target)); |
| 1188 | | if (needs_grouping) try argv.append("--end-group"); |
| 1189 | | } else if (target.isGnuLibC()) { |
| 1190 | | for (glibc.libs) |lib| { |
| 1191 | | const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{ |
| 1192 | | comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, |
| 1193 | | }); |
| 1194 | | try argv.append(lib_path); |
| 1195 | | } |
| 1196 | | try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a")); |
| 1197 | | } else if (target.isMusl()) { |
| 1198 | | try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { |
| 1199 | | .Static => "libc.a", |
| 1200 | | .Dynamic => "libc.so", |
| 1201 | | })); |
| 1202 | | } |
| 1203 | | } |
| 1204 | | |
| 1205 | | // compiler-rt |
| 1206 | | if (compiler_rt_path) |p| { |
| 1207 | | try argv.append(p); |
| 1208 | | } |
| 1209 | | |
| 1210 | | // crt postlude |
| 1211 | | if (csu.crtend) |v| try argv.append(v); |
| 1212 | | if (csu.crtn) |v| try argv.append(v); |
| 1213 | | |
| 1214 | | Compilation.dump_argv(argv.items); |
| 1215 | | } |
| 1216 | | |
| 1217 | 977 | if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self); |
| 978 | if (self.isStaticLib()) return self.flushStaticLib(comp, module_obj_path); |
| 979 | if (self.isObject()) return self.flushObject(comp, module_obj_path); |
| 1218 | 980 | |
| 1219 | 981 | // Here we will parse input positional and library files (if referenced). |
| 1220 | 982 | // This will roughly match in any linker backend we support. |
| ... | ... | @@ -1240,6 +1002,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1240 | 1002 | // rpaths |
| 1241 | 1003 | var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator); |
| 1242 | 1004 | defer rpath_table.deinit(); |
| 1005 | |
| 1243 | 1006 | for (self.base.options.rpath_list) |rpath| { |
| 1244 | 1007 | _ = try rpath_table.put(rpath, {}); |
| 1245 | 1008 | } |
| ... | ... | @@ -1388,8 +1151,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1388 | 1151 | try self.handleAndReportParseError(obj.path, err, &parse_ctx); |
| 1389 | 1152 | } |
| 1390 | 1153 | |
| 1391 | | if (self.isStaticLib()) return self.flushStaticLib(comp); |
| 1392 | | |
| 1393 | 1154 | // Init all objects |
| 1394 | 1155 | for (self.objects.items) |index| { |
| 1395 | 1156 | try self.file(index).?.object.init(self); |
| ... | ... | @@ -1418,7 +1179,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1418 | 1179 | |
| 1419 | 1180 | // If we haven't already, create a linker-generated input file comprising of |
| 1420 | 1181 | // linker-defined synthetic symbols only such as `_DYNAMIC`, etc. |
| 1421 | | if (self.linker_defined_index == null and !self.isRelocatable()) { |
| 1182 | if (self.linker_defined_index == null) { |
| 1422 | 1183 | const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); |
| 1423 | 1184 | self.files.set(index, .{ .linker_defined = .{ .index = index } }); |
| 1424 | 1185 | self.linker_defined_index = index; |
| ... | ... | @@ -1432,8 +1193,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1432 | 1193 | self.resolveSymbols(); |
| 1433 | 1194 | self.markEhFrameAtomsDead(); |
| 1434 | 1195 | |
| 1435 | | if (self.isObject()) return self.flushObject(comp); |
| 1436 | | |
| 1437 | 1196 | try self.convertCommonSymbols(); |
| 1438 | 1197 | self.markImportsExports(); |
| 1439 | 1198 | |
| ... | ... | @@ -1527,10 +1286,30 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1527 | 1286 | } |
| 1528 | 1287 | } |
| 1529 | 1288 | |
| 1530 | | pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void { |
| 1531 | | _ = comp; |
| 1289 | pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 1532 | 1290 | const gpa = self.base.allocator; |
| 1533 | 1291 | |
| 1292 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); |
| 1293 | defer positionals.deinit(); |
| 1294 | |
| 1295 | try positionals.ensureUnusedCapacity(self.base.options.objects.len); |
| 1296 | positionals.appendSliceAssumeCapacity(self.base.options.objects); |
| 1297 | |
| 1298 | // This is a set of object files emitted by clang in a single `build-exe` invocation. |
| 1299 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up |
| 1300 | // in this set. |
| 1301 | for (comp.c_object_table.keys()) |key| { |
| 1302 | try positionals.append(.{ .path = key.status.success.object_path }); |
| 1303 | } |
| 1304 | |
| 1305 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 1306 | |
| 1307 | for (positionals.items) |obj| { |
| 1308 | var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; |
| 1309 | self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err| |
| 1310 | try self.handleAndReportParseError(obj.path, err, &parse_ctx); |
| 1311 | } |
| 1312 | |
| 1534 | 1313 | // First, we flush relocatable object file generated with our backends. |
| 1535 | 1314 | if (self.zigObjectPtr()) |zig_object| { |
| 1536 | 1315 | zig_object.resolveSymbols(self); |
| ... | ... | @@ -1539,16 +1318,17 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void |
| 1539 | 1318 | try self.initSymtab(); |
| 1540 | 1319 | try self.initShStrtab(); |
| 1541 | 1320 | try self.sortShdrs(); |
| 1542 | | zig_object.updateRelaSectionSizes(self); |
| 1543 | | self.updateSymtabSizeObject(zig_object); |
| 1544 | | self.updateShStrtabSize(); |
| 1321 | try zig_object.addAtomsToRelaSections(self); |
| 1322 | try self.updateSectionSizesObject(); |
| 1545 | 1323 | |
| 1546 | 1324 | try self.allocateNonAllocSections(); |
| 1547 | 1325 | |
| 1326 | if (build_options.enable_logging) { |
| 1327 | state_log.debug("{}", .{self.dumpState()}); |
| 1328 | } |
| 1329 | |
| 1330 | try self.writeSyntheticSectionsObject(); |
| 1548 | 1331 | try self.writeShdrTable(); |
| 1549 | | try zig_object.writeRelaSections(self); |
| 1550 | | try self.writeSymtabObject(zig_object); |
| 1551 | | try self.writeShStrtab(); |
| 1552 | 1332 | try self.writeElfHeader(); |
| 1553 | 1333 | } |
| 1554 | 1334 | |
| ... | ... | @@ -1603,67 +1383,391 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void |
| 1603 | 1383 | pos += @sizeOf(elf.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow); |
| 1604 | 1384 | } |
| 1605 | 1385 | |
| 1606 | | break :blk pos; |
| 1607 | | }; |
| 1386 | break :blk pos; |
| 1387 | }; |
| 1388 | |
| 1389 | if (build_options.enable_logging) { |
| 1390 | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)}); |
| 1391 | state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); |
| 1392 | } |
| 1393 | |
| 1394 | var buffer = std.ArrayList(u8).init(gpa); |
| 1395 | defer buffer.deinit(); |
| 1396 | try buffer.ensureTotalCapacityPrecise(total_size); |
| 1397 | |
| 1398 | // Write magic |
| 1399 | try buffer.writer().writeAll(elf.ARMAG); |
| 1400 | |
| 1401 | // Write symtab |
| 1402 | try ar_symtab.write(.p64, self, buffer.writer()); |
| 1403 | |
| 1404 | // Write strtab |
| 1405 | if (ar_strtab.size() > 0) { |
| 1406 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); |
| 1407 | try ar_strtab.write(buffer.writer()); |
| 1408 | } |
| 1409 | |
| 1410 | // Write object files |
| 1411 | for (files.items) |index| { |
| 1412 | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); |
| 1413 | try self.file(index).?.writeAr(self, buffer.writer()); |
| 1414 | } |
| 1415 | |
| 1416 | assert(buffer.items.len == total_size); |
| 1417 | |
| 1418 | try self.base.file.?.setEndPos(total_size); |
| 1419 | try self.base.file.?.pwriteAll(buffer.items, 0); |
| 1420 | } |
| 1421 | |
| 1422 | pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8) link.File.FlushError!void { |
| 1423 | const gpa = self.base.allocator; |
| 1424 | |
| 1425 | var positionals = std.ArrayList(Compilation.LinkObject).init(gpa); |
| 1426 | defer positionals.deinit(); |
| 1427 | try positionals.ensureUnusedCapacity(self.base.options.objects.len); |
| 1428 | positionals.appendSliceAssumeCapacity(self.base.options.objects); |
| 1429 | |
| 1430 | // This is a set of object files emitted by clang in a single `build-exe` invocation. |
| 1431 | // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up |
| 1432 | // in this set. |
| 1433 | for (comp.c_object_table.keys()) |key| { |
| 1434 | try positionals.append(.{ .path = key.status.success.object_path }); |
| 1435 | } |
| 1436 | |
| 1437 | if (module_obj_path) |path| try positionals.append(.{ .path = path }); |
| 1438 | |
| 1439 | for (positionals.items) |obj| { |
| 1440 | var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined }; |
| 1441 | self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err| |
| 1442 | try self.handleAndReportParseError(obj.path, err, &parse_ctx); |
| 1443 | } |
| 1444 | |
| 1445 | // Init all objects |
| 1446 | for (self.objects.items) |index| { |
| 1447 | try self.file(index).?.object.init(self); |
| 1448 | } |
| 1449 | |
| 1450 | // Now, we are ready to resolve the symbols across all input files. |
| 1451 | // We will first resolve the files in the ZigObject, next in the parsed |
| 1452 | // input Object files. |
| 1453 | self.resolveSymbols(); |
| 1454 | self.markEhFrameAtomsDead(); |
| 1455 | self.claimUnresolvedObject(); |
| 1456 | |
| 1457 | try self.initSectionsObject(); |
| 1458 | try self.sortShdrs(); |
| 1459 | if (self.zigObjectPtr()) |zig_object| { |
| 1460 | try zig_object.addAtomsToRelaSections(self); |
| 1461 | } |
| 1462 | for (self.objects.items) |index| { |
| 1463 | const object = self.file(index).?.object; |
| 1464 | try object.addAtomsToOutputSections(self); |
| 1465 | try object.addAtomsToRelaSections(self); |
| 1466 | } |
| 1467 | try self.updateSectionSizesObject(); |
| 1468 | |
| 1469 | try self.allocateAllocSectionsObject(); |
| 1470 | try self.allocateNonAllocSections(); |
| 1471 | self.allocateAtoms(); |
| 1472 | |
| 1473 | if (build_options.enable_logging) { |
| 1474 | state_log.debug("{}", .{self.dumpState()}); |
| 1475 | } |
| 1476 | |
| 1477 | try self.writeAtomsObject(); |
| 1478 | try self.writeSyntheticSectionsObject(); |
| 1479 | try self.writeShdrTable(); |
| 1480 | try self.writeElfHeader(); |
| 1481 | } |
| 1482 | |
| 1483 | /// --verbose-link output |
| 1484 | fn dumpArgv(self: *Elf, comp: *Compilation) !void { |
| 1485 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); |
| 1486 | defer arena_allocator.deinit(); |
| 1487 | const arena = arena_allocator.allocator(); |
| 1488 | |
| 1489 | const target = self.base.options.target; |
| 1490 | const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. |
| 1491 | const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path}); |
| 1492 | const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: { |
| 1493 | if (fs.path.dirname(full_out_path)) |dirname| { |
| 1494 | break :blk try fs.path.join(arena, &.{ dirname, path }); |
| 1495 | } else { |
| 1496 | break :blk path; |
| 1497 | } |
| 1498 | } else null; |
| 1499 | const gc_sections = self.base.options.gc_sections orelse false; |
| 1500 | |
| 1501 | var csu = try CsuObjects.init(arena, self.base.options, comp); |
| 1502 | const compiler_rt_path: ?[]const u8 = blk: { |
| 1503 | if (comp.compiler_rt_lib) |x| break :blk x.full_object_path; |
| 1504 | if (comp.compiler_rt_obj) |x| break :blk x.full_object_path; |
| 1505 | break :blk null; |
| 1506 | }; |
| 1507 | |
| 1508 | var argv = std.ArrayList([]const u8).init(arena); |
| 1509 | |
| 1510 | try argv.append("zig"); |
| 1511 | |
| 1512 | if (self.isStaticLib()) { |
| 1513 | try argv.append("ar"); |
| 1514 | } else { |
| 1515 | try argv.append("ld"); |
| 1516 | } |
| 1517 | |
| 1518 | if (self.isObject()) { |
| 1519 | try argv.append("-r"); |
| 1520 | } |
| 1521 | |
| 1522 | try argv.append("-o"); |
| 1523 | try argv.append(full_out_path); |
| 1524 | |
| 1525 | if (self.isRelocatable()) { |
| 1526 | for (self.base.options.objects) |obj| { |
| 1527 | try argv.append(obj.path); |
| 1528 | } |
| 1529 | |
| 1530 | for (comp.c_object_table.keys()) |key| { |
| 1531 | try argv.append(key.status.success.object_path); |
| 1532 | } |
| 1533 | |
| 1534 | if (module_obj_path) |p| { |
| 1535 | try argv.append(p); |
| 1536 | } |
| 1537 | } else { |
| 1538 | if (!self.isStatic()) { |
| 1539 | if (self.base.options.dynamic_linker) |path| { |
| 1540 | try argv.append("-dynamic-linker"); |
| 1541 | try argv.append(path); |
| 1542 | } |
| 1543 | } |
| 1544 | |
| 1545 | if (self.isDynLib()) { |
| 1546 | if (self.base.options.soname) |name| { |
| 1547 | try argv.append("-soname"); |
| 1548 | try argv.append(name); |
| 1549 | } |
| 1550 | } |
| 1551 | |
| 1552 | if (self.base.options.entry) |entry| { |
| 1553 | try argv.append("--entry"); |
| 1554 | try argv.append(entry); |
| 1555 | } |
| 1556 | |
| 1557 | for (self.base.options.rpath_list) |rpath| { |
| 1558 | try argv.append("-rpath"); |
| 1559 | try argv.append(rpath); |
| 1560 | } |
| 1561 | |
| 1562 | if (self.base.options.each_lib_rpath) { |
| 1563 | for (self.base.options.lib_dirs) |lib_dir_path| { |
| 1564 | try argv.append("-rpath"); |
| 1565 | try argv.append(lib_dir_path); |
| 1566 | } |
| 1567 | for (self.base.options.objects) |obj| { |
| 1568 | if (Compilation.classifyFileExt(obj.path) == .shared_library) { |
| 1569 | const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue; |
| 1570 | if (obj.loption) continue; |
| 1571 | |
| 1572 | try argv.append("-rpath"); |
| 1573 | try argv.append(lib_dir_path); |
| 1574 | } |
| 1575 | } |
| 1576 | } |
| 1577 | |
| 1578 | if (self.base.options.stack_size_override) |ss| { |
| 1579 | try argv.append("-z"); |
| 1580 | try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss})); |
| 1581 | } |
| 1582 | |
| 1583 | if (self.base.options.image_base_override) |image_base| { |
| 1584 | try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base})); |
| 1585 | } |
| 1586 | |
| 1587 | if (gc_sections) { |
| 1588 | try argv.append("--gc-sections"); |
| 1589 | } |
| 1590 | |
| 1591 | if (self.base.options.print_gc_sections) { |
| 1592 | try argv.append("--print-gc-sections"); |
| 1593 | } |
| 1594 | |
| 1595 | if (self.base.options.eh_frame_hdr) { |
| 1596 | try argv.append("--eh-frame-hdr"); |
| 1597 | } |
| 1598 | |
| 1599 | if (self.base.options.rdynamic) { |
| 1600 | try argv.append("--export-dynamic"); |
| 1601 | } |
| 1602 | |
| 1603 | if (self.base.options.z_notext) { |
| 1604 | try argv.append("-z"); |
| 1605 | try argv.append("notext"); |
| 1606 | } |
| 1607 | |
| 1608 | if (self.base.options.z_nocopyreloc) { |
| 1609 | try argv.append("-z"); |
| 1610 | try argv.append("nocopyreloc"); |
| 1611 | } |
| 1612 | |
| 1613 | if (self.base.options.z_now) { |
| 1614 | try argv.append("-z"); |
| 1615 | try argv.append("now"); |
| 1616 | } |
| 1617 | |
| 1618 | if (self.isStatic()) { |
| 1619 | try argv.append("-static"); |
| 1620 | } else if (self.isDynLib()) { |
| 1621 | try argv.append("-shared"); |
| 1622 | } |
| 1623 | |
| 1624 | if (self.base.options.pie and self.isExe()) { |
| 1625 | try argv.append("-pie"); |
| 1626 | } |
| 1627 | |
| 1628 | if (self.base.options.strip) { |
| 1629 | try argv.append("-s"); |
| 1630 | } |
| 1631 | |
| 1632 | // csu prelude |
| 1633 | if (csu.crt0) |v| try argv.append(v); |
| 1634 | if (csu.crti) |v| try argv.append(v); |
| 1635 | if (csu.crtbegin) |v| try argv.append(v); |
| 1636 | |
| 1637 | for (self.base.options.lib_dirs) |lib_dir| { |
| 1638 | try argv.append("-L"); |
| 1639 | try argv.append(lib_dir); |
| 1640 | } |
| 1641 | |
| 1642 | if (self.base.options.link_libc) { |
| 1643 | if (self.base.options.libc_installation) |libc_installation| { |
| 1644 | try argv.append("-L"); |
| 1645 | try argv.append(libc_installation.crt_dir.?); |
| 1646 | } |
| 1647 | } |
| 1608 | 1648 | |
| 1609 | | if (build_options.enable_logging) { |
| 1610 | | state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)}); |
| 1611 | | state_log.debug("ar_strtab\n{}\n", .{ar_strtab}); |
| 1612 | | } |
| 1649 | var whole_archive = false; |
| 1650 | for (self.base.options.objects) |obj| { |
| 1651 | if (obj.must_link and !whole_archive) { |
| 1652 | try argv.append("-whole-archive"); |
| 1653 | whole_archive = true; |
| 1654 | } else if (!obj.must_link and whole_archive) { |
| 1655 | try argv.append("-no-whole-archive"); |
| 1656 | whole_archive = false; |
| 1657 | } |
| 1613 | 1658 | |
| 1614 | | var buffer = std.ArrayList(u8).init(gpa); |
| 1615 | | defer buffer.deinit(); |
| 1616 | | try buffer.ensureTotalCapacityPrecise(total_size); |
| 1659 | if (obj.loption) { |
| 1660 | assert(obj.path[0] == ':'); |
| 1661 | try argv.append("-l"); |
| 1662 | } |
| 1663 | try argv.append(obj.path); |
| 1664 | } |
| 1665 | if (whole_archive) { |
| 1666 | try argv.append("-no-whole-archive"); |
| 1667 | whole_archive = false; |
| 1668 | } |
| 1617 | 1669 | |
| 1618 | | // Write magic |
| 1619 | | try buffer.writer().writeAll(elf.ARMAG); |
| 1670 | for (comp.c_object_table.keys()) |key| { |
| 1671 | try argv.append(key.status.success.object_path); |
| 1672 | } |
| 1620 | 1673 | |
| 1621 | | // Write symtab |
| 1622 | | try ar_symtab.write(.p64, self, buffer.writer()); |
| 1674 | if (module_obj_path) |p| { |
| 1675 | try argv.append(p); |
| 1676 | } |
| 1623 | 1677 | |
| 1624 | | // Write strtab |
| 1625 | | if (ar_strtab.size() > 0) { |
| 1626 | | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); |
| 1627 | | try ar_strtab.write(buffer.writer()); |
| 1628 | | } |
| 1678 | // TSAN |
| 1679 | if (self.base.options.tsan) { |
| 1680 | try argv.append(comp.tsan_static_lib.?.full_object_path); |
| 1681 | } |
| 1629 | 1682 | |
| 1630 | | // Write object files |
| 1631 | | for (files.items) |index| { |
| 1632 | | if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0); |
| 1633 | | try self.file(index).?.writeAr(self, buffer.writer()); |
| 1634 | | } |
| 1683 | // libc |
| 1684 | if (!self.base.options.skip_linker_dependencies and |
| 1685 | !self.base.options.link_libc) |
| 1686 | { |
| 1687 | if (comp.libc_static_lib) |lib| { |
| 1688 | try argv.append(lib.full_object_path); |
| 1689 | } |
| 1690 | } |
| 1635 | 1691 | |
| 1636 | | assert(buffer.items.len == total_size); |
| 1692 | // stack-protector. |
| 1693 | // Related: https://github.com/ziglang/zig/issues/7265 |
| 1694 | if (comp.libssp_static_lib) |ssp| { |
| 1695 | try argv.append(ssp.full_object_path); |
| 1696 | } |
| 1637 | 1697 | |
| 1638 | | try self.base.file.?.setEndPos(total_size); |
| 1639 | | try self.base.file.?.pwriteAll(buffer.items, 0); |
| 1640 | | } |
| 1698 | // Shared libraries. |
| 1699 | // Worst-case, we need an --as-needed argument for every lib, as well |
| 1700 | // as one before and one after. |
| 1701 | try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2); |
| 1702 | argv.appendAssumeCapacity("--as-needed"); |
| 1703 | var as_needed = true; |
| 1641 | 1704 | |
| 1642 | | pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void { |
| 1643 | | _ = comp; |
| 1705 | for (self.base.options.system_libs.values()) |lib_info| { |
| 1706 | const lib_as_needed = !lib_info.needed; |
| 1707 | switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) { |
| 1708 | 0b00, 0b11 => {}, |
| 1709 | 0b01 => { |
| 1710 | argv.appendAssumeCapacity("--no-as-needed"); |
| 1711 | as_needed = false; |
| 1712 | }, |
| 1713 | 0b10 => { |
| 1714 | argv.appendAssumeCapacity("--as-needed"); |
| 1715 | as_needed = true; |
| 1716 | }, |
| 1717 | } |
| 1718 | argv.appendAssumeCapacity(lib_info.path.?); |
| 1719 | } |
| 1644 | 1720 | |
| 1645 | | if (self.objects.items.len > 0) { |
| 1646 | | var err = try self.addErrorWithNotes(1); |
| 1647 | | try err.addMsg(self, "fatal linker error: too many input positionals", .{}); |
| 1648 | | try err.addNote(self, "TODO implement '-r' option", .{}); |
| 1649 | | return; |
| 1650 | | } |
| 1721 | if (!as_needed) { |
| 1722 | argv.appendAssumeCapacity("--as-needed"); |
| 1723 | as_needed = true; |
| 1724 | } |
| 1651 | 1725 | |
| 1652 | | self.claimUnresolvedObject(); |
| 1726 | // libc++ dep |
| 1727 | if (self.base.options.link_libcpp) { |
| 1728 | try argv.append(comp.libcxxabi_static_lib.?.full_object_path); |
| 1729 | try argv.append(comp.libcxx_static_lib.?.full_object_path); |
| 1730 | } |
| 1653 | 1731 | |
| 1654 | | try self.initSections(); |
| 1655 | | try self.sortShdrs(); |
| 1656 | | try self.updateSectionSizes(); |
| 1732 | // libunwind dep |
| 1733 | if (self.base.options.link_libunwind) { |
| 1734 | try argv.append(comp.libunwind_static_lib.?.full_object_path); |
| 1735 | } |
| 1657 | 1736 | |
| 1658 | | try self.allocateNonAllocSections(); |
| 1737 | // libc dep |
| 1738 | if (self.base.options.link_libc) { |
| 1739 | if (self.base.options.libc_installation != null) { |
| 1740 | const needs_grouping = self.base.options.link_mode == .Static; |
| 1741 | if (needs_grouping) try argv.append("--start-group"); |
| 1742 | try argv.appendSlice(target_util.libcFullLinkFlags(target)); |
| 1743 | if (needs_grouping) try argv.append("--end-group"); |
| 1744 | } else if (target.isGnuLibC()) { |
| 1745 | for (glibc.libs) |lib| { |
| 1746 | const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{ |
| 1747 | comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover, |
| 1748 | }); |
| 1749 | try argv.append(lib_path); |
| 1750 | } |
| 1751 | try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a")); |
| 1752 | } else if (target.isMusl()) { |
| 1753 | try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) { |
| 1754 | .Static => "libc.a", |
| 1755 | .Dynamic => "libc.so", |
| 1756 | })); |
| 1757 | } |
| 1758 | } |
| 1659 | 1759 | |
| 1660 | | if (build_options.enable_logging) { |
| 1661 | | state_log.debug("{}", .{self.dumpState()}); |
| 1760 | // compiler-rt |
| 1761 | if (compiler_rt_path) |p| { |
| 1762 | try argv.append(p); |
| 1763 | } |
| 1764 | |
| 1765 | // crt postlude |
| 1766 | if (csu.crtend) |v| try argv.append(v); |
| 1767 | if (csu.crtn) |v| try argv.append(v); |
| 1662 | 1768 | } |
| 1663 | 1769 | |
| 1664 | | try self.writeShdrTable(); |
| 1665 | | try self.writeSyntheticSections(); |
| 1666 | | try self.writeElfHeader(); |
| 1770 | Compilation.dump_argv(argv.items); |
| 1667 | 1771 | } |
| 1668 | 1772 | |
| 1669 | 1773 | const ParseError = error{ |
| ... | ... | @@ -2047,8 +2151,7 @@ fn claimUnresolved(self: *Elf) void { |
| 2047 | 2151 | zig_object.claimUnresolved(self); |
| 2048 | 2152 | } |
| 2049 | 2153 | for (self.objects.items) |index| { |
| 2050 | | const object = self.file(index).?.object; |
| 2051 | | object.claimUnresolved(self); |
| 2154 | self.file(index).?.object.claimUnresolved(self); |
| 2052 | 2155 | } |
| 2053 | 2156 | } |
| 2054 | 2157 | |
| ... | ... | @@ -2056,6 +2159,9 @@ fn claimUnresolvedObject(self: *Elf) void { |
| 2056 | 2159 | if (self.zigObjectPtr()) |zig_object| { |
| 2057 | 2160 | zig_object.claimUnresolvedObject(self); |
| 2058 | 2161 | } |
| 2162 | for (self.objects.items) |index| { |
| 2163 | self.file(index).?.object.claimUnresolvedObject(self); |
| 2164 | } |
| 2059 | 2165 | } |
| 2060 | 2166 | |
| 2061 | 2167 | /// In scanRelocs we will go over all live atoms and scan their relocs. |
| ... | ... | @@ -3460,6 +3566,60 @@ fn initSections(self: *Elf) !void { |
| 3460 | 3566 | try self.initShStrtab(); |
| 3461 | 3567 | } |
| 3462 | 3568 | |
| 3569 | fn initSectionsObject(self: *Elf) !void { |
| 3570 | const ptr_size = self.ptrWidthBytes(); |
| 3571 | |
| 3572 | for (self.objects.items) |index| { |
| 3573 | const object = self.file(index).?.object; |
| 3574 | try object.initOutputSections(self); |
| 3575 | try object.initRelaSections(self); |
| 3576 | } |
| 3577 | |
| 3578 | const needs_eh_frame = for (self.objects.items) |index| { |
| 3579 | if (self.file(index).?.object.cies.items.len > 0) break true; |
| 3580 | } else false; |
| 3581 | if (needs_eh_frame) { |
| 3582 | self.eh_frame_section_index = try self.addSection(.{ |
| 3583 | .name = ".eh_frame", |
| 3584 | .type = elf.SHT_PROGBITS, |
| 3585 | .flags = elf.SHF_ALLOC, |
| 3586 | .addralign = ptr_size, |
| 3587 | .offset = std.math.maxInt(u64), |
| 3588 | }); |
| 3589 | self.eh_frame_rela_section_index = try self.addRelaShdr(".rela.eh_frame", self.eh_frame_section_index.?); |
| 3590 | } |
| 3591 | |
| 3592 | try self.initComdatGroups(); |
| 3593 | try self.initSymtab(); |
| 3594 | try self.initShStrtab(); |
| 3595 | } |
| 3596 | |
| 3597 | fn initComdatGroups(self: *Elf) !void { |
| 3598 | const gpa = self.base.allocator; |
| 3599 | |
| 3600 | for (self.objects.items) |index| { |
| 3601 | const object = self.file(index).?.object; |
| 3602 | |
| 3603 | for (object.comdat_groups.items) |cg_index| { |
| 3604 | const cg = self.comdatGroup(cg_index); |
| 3605 | const cg_owner = self.comdatGroupOwner(cg.owner); |
| 3606 | if (cg_owner.file != index) continue; |
| 3607 | |
| 3608 | const cg_sec = try self.comdat_group_sections.addOne(gpa); |
| 3609 | cg_sec.* = .{ |
| 3610 | .shndx = try self.addSection(.{ |
| 3611 | .name = ".group", |
| 3612 | .type = elf.SHT_GROUP, |
| 3613 | .entsize = @sizeOf(u32), |
| 3614 | .addralign = @alignOf(u32), |
| 3615 | .offset = std.math.maxInt(u64), |
| 3616 | }), |
| 3617 | .cg_index = cg_index, |
| 3618 | }; |
| 3619 | } |
| 3620 | } |
| 3621 | } |
| 3622 | |
| 3463 | 3623 | fn initSymtab(self: *Elf) !void { |
| 3464 | 3624 | const small_ptr = switch (self.ptr_width) { |
| 3465 | 3625 | .p32 => true, |
| ... | ... | @@ -3586,7 +3746,8 @@ fn sortInitFini(self: *Elf) !void { |
| 3586 | 3746 | |
| 3587 | 3747 | if (!is_init_fini and !is_ctor_dtor) continue; |
| 3588 | 3748 | |
| 3589 | | const atom_list = self.output_sections.getPtr(@intCast(shndx)) orelse continue; |
| 3749 | const atom_list = self.output_sections.getPtr(@intCast(shndx)).?; |
| 3750 | if (atom_list.items.len == 0) continue; |
| 3590 | 3751 | |
| 3591 | 3752 | var entries = std.ArrayList(Entry).init(gpa); |
| 3592 | 3753 | try entries.ensureTotalCapacityPrecise(atom_list.items.len); |
| ... | ... | @@ -3627,8 +3788,10 @@ fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void { |
| 3627 | 3788 | try self.dynamic.addNeeded(shared_object, self); |
| 3628 | 3789 | } |
| 3629 | 3790 | |
| 3630 | | if (self.base.options.soname) |soname| { |
| 3631 | | try self.dynamic.setSoname(soname, self); |
| 3791 | if (self.isDynLib()) { |
| 3792 | if (self.base.options.soname) |soname| { |
| 3793 | try self.dynamic.setSoname(soname, self); |
| 3794 | } |
| 3632 | 3795 | } |
| 3633 | 3796 | |
| 3634 | 3797 | try self.dynamic.setRpath(rpaths, self); |
| ... | ... | @@ -3760,7 +3923,7 @@ fn shdrRank(self: *Elf, shndx: u16) u8 { |
| 3760 | 3923 | |
| 3761 | 3924 | elf.SHT_DYNAMIC => return 0xf3, |
| 3762 | 3925 | |
| 3763 | | elf.SHT_RELA => return 0xf, |
| 3926 | elf.SHT_RELA, elf.SHT_GROUP => return 0xf, |
| 3764 | 3927 | |
| 3765 | 3928 | elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) { |
| 3766 | 3929 | if (flags & elf.SHF_EXECINSTR != 0) { |
| ... | ... | @@ -3819,8 +3982,15 @@ fn sortShdrs(self: *Elf) !void { |
| 3819 | 3982 | self.shdrs.appendAssumeCapacity(slice[sorted.shndx]); |
| 3820 | 3983 | } |
| 3821 | 3984 | |
| 3985 | try self.resetShdrIndexes(backlinks); |
| 3986 | } |
| 3987 | |
| 3988 | fn resetShdrIndexes(self: *Elf, backlinks: []const u16) !void { |
| 3989 | const gpa = self.base.allocator; |
| 3990 | |
| 3822 | 3991 | for (&[_]*?u16{ |
| 3823 | 3992 | &self.eh_frame_section_index, |
| 3993 | &self.eh_frame_rela_section_index, |
| 3824 | 3994 | &self.eh_frame_hdr_section_index, |
| 3825 | 3995 | &self.got_section_index, |
| 3826 | 3996 | &self.symtab_section_index, |
| ... | ... | @@ -3841,12 +4011,9 @@ fn sortShdrs(self: *Elf) !void { |
| 3841 | 4011 | &self.versym_section_index, |
| 3842 | 4012 | &self.verneed_section_index, |
| 3843 | 4013 | &self.zig_text_section_index, |
| 3844 | | &self.zig_text_rela_section_index, |
| 3845 | 4014 | &self.zig_got_section_index, |
| 3846 | 4015 | &self.zig_data_rel_ro_section_index, |
| 3847 | | &self.zig_data_rel_ro_rela_section_index, |
| 3848 | 4016 | &self.zig_data_section_index, |
| 3849 | | &self.zig_data_rela_section_index, |
| 3850 | 4017 | &self.zig_bss_section_index, |
| 3851 | 4018 | &self.debug_str_section_index, |
| 3852 | 4019 | &self.debug_info_section_index, |
| ... | ... | @@ -3905,15 +4072,39 @@ fn sortShdrs(self: *Elf) !void { |
| 3905 | 4072 | shdr.sh_info = self.plt_section_index.?; |
| 3906 | 4073 | } |
| 3907 | 4074 | |
| 3908 | | for (&[_]?u16{ |
| 3909 | | self.zig_text_rela_section_index, |
| 3910 | | self.zig_data_rel_ro_rela_section_index, |
| 3911 | | self.zig_data_rela_section_index, |
| 3912 | | }) |maybe_index| { |
| 3913 | | const index = maybe_index orelse continue; |
| 4075 | if (self.eh_frame_rela_section_index) |index| { |
| 3914 | 4076 | const shdr = &self.shdrs.items[index]; |
| 3915 | 4077 | shdr.sh_link = self.symtab_section_index.?; |
| 3916 | | shdr.sh_info = backlinks[shdr.sh_info]; |
| 4078 | shdr.sh_info = self.eh_frame_section_index.?; |
| 4079 | } |
| 4080 | |
| 4081 | { |
| 4082 | var output_sections = try self.output_sections.clone(gpa); |
| 4083 | defer output_sections.deinit(gpa); |
| 4084 | |
| 4085 | self.output_sections.clearRetainingCapacity(); |
| 4086 | |
| 4087 | var it = output_sections.iterator(); |
| 4088 | while (it.next()) |entry| { |
| 4089 | const shndx = entry.key_ptr.*; |
| 4090 | const meta = entry.value_ptr.*; |
| 4091 | self.output_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta); |
| 4092 | } |
| 4093 | } |
| 4094 | |
| 4095 | { |
| 4096 | var output_rela_sections = try self.output_rela_sections.clone(gpa); |
| 4097 | defer output_rela_sections.deinit(gpa); |
| 4098 | |
| 4099 | self.output_rela_sections.clearRetainingCapacity(); |
| 4100 | |
| 4101 | var it = output_rela_sections.iterator(); |
| 4102 | while (it.next()) |entry| { |
| 4103 | const shndx = entry.key_ptr.*; |
| 4104 | var meta = entry.value_ptr.*; |
| 4105 | meta.shndx = backlinks[meta.shndx]; |
| 4106 | self.output_rela_sections.putAssumeCapacityNoClobber(backlinks[shndx], meta); |
| 4107 | } |
| 3917 | 4108 | } |
| 3918 | 4109 | |
| 3919 | 4110 | { |
| ... | ... | @@ -3965,11 +4156,20 @@ fn sortShdrs(self: *Elf) !void { |
| 3965 | 4156 | global.output_section_index = backlinks[out_shndx]; |
| 3966 | 4157 | } |
| 3967 | 4158 | } |
| 4159 | |
| 4160 | for (self.output_rela_sections.keys(), self.output_rela_sections.values()) |shndx, sec| { |
| 4161 | const shdr = &self.shdrs.items[sec.shndx]; |
| 4162 | shdr.sh_link = self.symtab_section_index.?; |
| 4163 | shdr.sh_info = shndx; |
| 4164 | } |
| 4165 | |
| 4166 | for (self.comdat_group_sections.items) |*cg| { |
| 4167 | cg.shndx = backlinks[cg.shndx]; |
| 4168 | } |
| 3968 | 4169 | } |
| 3969 | 4170 | |
| 3970 | 4171 | fn updateSectionSizes(self: *Elf) !void { |
| 3971 | 4172 | for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { |
| 3972 | | if (atom_list.items.len == 0) continue; |
| 3973 | 4173 | const shdr = &self.shdrs.items[shndx]; |
| 3974 | 4174 | for (atom_list.items) |atom_index| { |
| 3975 | 4175 | const atom_ptr = self.atom(atom_index) orelse continue; |
| ... | ... | @@ -3982,10 +4182,6 @@ fn updateSectionSizes(self: *Elf) !void { |
| 3982 | 4182 | } |
| 3983 | 4183 | } |
| 3984 | 4184 | |
| 3985 | | if (self.zigObjectPtr()) |zig_object| { |
| 3986 | | zig_object.updateRelaSectionSizes(self); |
| 3987 | | } |
| 3988 | | |
| 3989 | 4185 | if (self.eh_frame_section_index) |index| { |
| 3990 | 4186 | self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); |
| 3991 | 4187 | } |
| ... | ... | @@ -4049,22 +4245,73 @@ fn updateSectionSizes(self: *Elf) !void { |
| 4049 | 4245 | self.shdrs.items[index].sh_size = self.dynsym.size(); |
| 4050 | 4246 | } |
| 4051 | 4247 | |
| 4052 | | if (self.dynstrtab_section_index) |index| { |
| 4053 | | self.shdrs.items[index].sh_size = self.dynstrtab.items.len; |
| 4054 | | } |
| 4248 | if (self.dynstrtab_section_index) |index| { |
| 4249 | self.shdrs.items[index].sh_size = self.dynstrtab.items.len; |
| 4250 | } |
| 4251 | |
| 4252 | if (self.versym_section_index) |index| { |
| 4253 | self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym); |
| 4254 | } |
| 4255 | |
| 4256 | if (self.verneed_section_index) |index| { |
| 4257 | self.shdrs.items[index].sh_size = self.verneed.size(); |
| 4258 | } |
| 4259 | |
| 4260 | try self.updateSymtabSize(); |
| 4261 | self.updateShStrtabSize(); |
| 4262 | } |
| 4263 | |
| 4264 | fn updateSectionSizesObject(self: *Elf) !void { |
| 4265 | for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| { |
| 4266 | const shdr = &self.shdrs.items[shndx]; |
| 4267 | for (atom_list.items) |atom_index| { |
| 4268 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 4269 | if (!atom_ptr.flags.alive) continue; |
| 4270 | const offset = atom_ptr.alignment.forward(shdr.sh_size); |
| 4271 | const padding = offset - shdr.sh_size; |
| 4272 | atom_ptr.value = offset; |
| 4273 | shdr.sh_size += padding + atom_ptr.size; |
| 4274 | shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1)); |
| 4275 | } |
| 4276 | } |
| 4277 | |
| 4278 | for (self.output_rela_sections.values()) |sec| { |
| 4279 | const shdr = &self.shdrs.items[sec.shndx]; |
| 4280 | for (sec.atom_list.items) |atom_index| { |
| 4281 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 4282 | if (!atom_ptr.flags.alive) continue; |
| 4283 | const relocs = atom_ptr.relocs(self); |
| 4284 | shdr.sh_size += shdr.sh_entsize * relocs.len; |
| 4285 | } |
| 4055 | 4286 | |
| 4056 | | if (self.versym_section_index) |index| { |
| 4057 | | self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym); |
| 4287 | if (shdr.sh_size == 0) shdr.sh_offset = 0; |
| 4058 | 4288 | } |
| 4059 | 4289 | |
| 4060 | | if (self.verneed_section_index) |index| { |
| 4061 | | self.shdrs.items[index].sh_size = self.verneed.size(); |
| 4290 | if (self.eh_frame_section_index) |index| { |
| 4291 | self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self); |
| 4292 | } |
| 4293 | if (self.eh_frame_rela_section_index) |index| { |
| 4294 | const shdr = &self.shdrs.items[index]; |
| 4295 | shdr.sh_size = eh_frame.calcEhFrameRelocs(self) * shdr.sh_entsize; |
| 4062 | 4296 | } |
| 4063 | 4297 | |
| 4064 | | self.updateSymtabSize(); |
| 4298 | try self.updateSymtabSize(); |
| 4299 | self.updateComdatGroupsSizes(); |
| 4065 | 4300 | self.updateShStrtabSize(); |
| 4066 | 4301 | } |
| 4067 | 4302 | |
| 4303 | fn updateComdatGroupsSizes(self: *Elf) void { |
| 4304 | for (self.comdat_group_sections.items) |cg| { |
| 4305 | const shdr = &self.shdrs.items[cg.shndx]; |
| 4306 | shdr.sh_size = cg.size(self); |
| 4307 | shdr.sh_link = self.symtab_section_index.?; |
| 4308 | |
| 4309 | const sym = self.symbol(cg.symbol(self)); |
| 4310 | shdr.sh_info = sym.outputSymtabIndex(self) orelse |
| 4311 | self.sectionSymbolOutputSymtabIndex(sym.outputShndx().?); |
| 4312 | } |
| 4313 | } |
| 4314 | |
| 4068 | 4315 | fn updateShStrtabSize(self: *Elf) void { |
| 4069 | 4316 | if (self.shstrtab_section_index) |index| { |
| 4070 | 4317 | self.shdrs.items[index].sh_size = self.shstrtab.items.len; |
| ... | ... | @@ -4294,6 +4541,22 @@ fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void { |
| 4294 | 4541 | } |
| 4295 | 4542 | } |
| 4296 | 4543 | |
| 4544 | /// Allocates alloc sections when merging relocatable objects files together. |
| 4545 | fn allocateAllocSectionsObject(self: *Elf) !void { |
| 4546 | for (self.shdrs.items) |*shdr| { |
| 4547 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4548 | if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue; |
| 4549 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 4550 | const needed_size = shdr.sh_size; |
| 4551 | if (needed_size > self.allocatedSize(shdr.sh_offset)) { |
| 4552 | shdr.sh_size = 0; |
| 4553 | const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign); |
| 4554 | shdr.sh_offset = new_offset; |
| 4555 | shdr.sh_size = needed_size; |
| 4556 | } |
| 4557 | } |
| 4558 | } |
| 4559 | |
| 4297 | 4560 | /// Allocates non-alloc sections (debug info, symtabs, etc.). |
| 4298 | 4561 | fn allocateNonAllocSections(self: *Elf) !void { |
| 4299 | 4562 | for (self.shdrs.items, 0..) |*shdr, shndx| { |
| ... | ... | @@ -4418,6 +4681,7 @@ fn writeAtoms(self: *Elf) !void { |
| 4418 | 4681 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 4419 | 4682 | |
| 4420 | 4683 | const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue; |
| 4684 | if (atom_list.items.len == 0) continue; |
| 4421 | 4685 | |
| 4422 | 4686 | log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); |
| 4423 | 4687 | |
| ... | ... | @@ -4484,93 +4748,165 @@ fn writeAtoms(self: *Elf) !void { |
| 4484 | 4748 | try self.reportUndefined(&undefs); |
| 4485 | 4749 | } |
| 4486 | 4750 | |
| 4487 | | fn updateSymtabSize(self: *Elf) void { |
| 4488 | | var sizes = SymtabSize{}; |
| 4751 | fn writeAtomsObject(self: *Elf) !void { |
| 4752 | const gpa = self.base.allocator; |
| 4489 | 4753 | |
| 4490 | | if (self.zigObjectPtr()) |zig_object| { |
| 4491 | | zig_object.asFile().updateSymtabSize(self); |
| 4492 | | sizes.add(zig_object.output_symtab_size); |
| 4754 | // TODO iterate over `output_sections` directly |
| 4755 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 4756 | if (shdr.sh_type == elf.SHT_NULL) continue; |
| 4757 | if (shdr.sh_type == elf.SHT_NOBITS) continue; |
| 4758 | |
| 4759 | const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue; |
| 4760 | if (atom_list.items.len == 0) continue; |
| 4761 | |
| 4762 | log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)}); |
| 4763 | |
| 4764 | // TODO really, really handle debug section separately |
| 4765 | const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: { |
| 4766 | const zig_object = self.zigObjectPtr().?; |
| 4767 | if (shndx == self.debug_info_section_index.?) |
| 4768 | break :blk zig_object.debug_info_section_zig_size; |
| 4769 | if (shndx == self.debug_abbrev_section_index.?) |
| 4770 | break :blk zig_object.debug_abbrev_section_zig_size; |
| 4771 | if (shndx == self.debug_str_section_index.?) |
| 4772 | break :blk zig_object.debug_str_section_zig_size; |
| 4773 | if (shndx == self.debug_aranges_section_index.?) |
| 4774 | break :blk zig_object.debug_aranges_section_zig_size; |
| 4775 | if (shndx == self.debug_line_section_index.?) |
| 4776 | break :blk zig_object.debug_line_section_zig_size; |
| 4777 | unreachable; |
| 4778 | } else 0; |
| 4779 | const sh_offset = shdr.sh_offset + base_offset; |
| 4780 | const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow; |
| 4781 | |
| 4782 | const buffer = try gpa.alloc(u8, sh_size); |
| 4783 | defer gpa.free(buffer); |
| 4784 | const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and |
| 4785 | shdr.sh_flags & elf.SHF_EXECINSTR != 0) |
| 4786 | 0xcc // int3 |
| 4787 | else |
| 4788 | 0; |
| 4789 | @memset(buffer, padding_byte); |
| 4790 | |
| 4791 | for (atom_list.items) |atom_index| { |
| 4792 | const atom_ptr = self.atom(atom_index).?; |
| 4793 | assert(atom_ptr.flags.alive); |
| 4794 | |
| 4795 | const object = atom_ptr.file(self).?.object; |
| 4796 | const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse |
| 4797 | return error.Overflow; |
| 4798 | const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow; |
| 4799 | |
| 4800 | log.debug("writing atom({d}) from 0x{x} to 0x{x}", .{ |
| 4801 | atom_index, |
| 4802 | sh_offset + offset, |
| 4803 | sh_offset + offset + size, |
| 4804 | }); |
| 4805 | |
| 4806 | // TODO decompress directly into provided buffer |
| 4807 | const out_code = buffer[offset..][0..size]; |
| 4808 | const in_code = try object.codeDecompressAlloc(self, atom_index); |
| 4809 | defer gpa.free(in_code); |
| 4810 | @memcpy(out_code, in_code); |
| 4811 | } |
| 4812 | |
| 4813 | try self.base.file.?.pwriteAll(buffer, sh_offset); |
| 4493 | 4814 | } |
| 4815 | } |
| 4816 | |
| 4817 | fn updateSymtabSize(self: *Elf) !void { |
| 4818 | var nlocals: u32 = 0; |
| 4819 | var nglobals: u32 = 0; |
| 4820 | var strsize: u32 = 0; |
| 4821 | |
| 4822 | const gpa = self.base.allocator; |
| 4823 | var files = std.ArrayList(File.Index).init(gpa); |
| 4824 | defer files.deinit(); |
| 4825 | try files.ensureTotalCapacityPrecise(self.objects.items.len + self.shared_objects.items.len + 1); |
| 4494 | 4826 | |
| 4827 | if (self.zig_object_index) |index| files.appendAssumeCapacity(index); |
| 4495 | 4828 | for (self.objects.items) |index| { |
| 4496 | | const file_ptr = self.file(index).?; |
| 4497 | | file_ptr.updateSymtabSize(self); |
| 4498 | | sizes.add(file_ptr.object.output_symtab_size); |
| 4829 | files.appendAssumeCapacity(index); |
| 4499 | 4830 | } |
| 4500 | | |
| 4501 | 4831 | for (self.shared_objects.items) |index| { |
| 4832 | files.appendAssumeCapacity(index); |
| 4833 | } |
| 4834 | |
| 4835 | // Section symbols |
| 4836 | for (self.output_sections.keys()) |_| { |
| 4837 | nlocals += 1; |
| 4838 | } |
| 4839 | if (self.eh_frame_section_index) |_| { |
| 4840 | nlocals += 1; |
| 4841 | } |
| 4842 | |
| 4843 | for (files.items) |index| { |
| 4502 | 4844 | const file_ptr = self.file(index).?; |
| 4503 | | file_ptr.updateSymtabSize(self); |
| 4504 | | sizes.add(file_ptr.shared_object.output_symtab_size); |
| 4845 | const ctx = switch (file_ptr) { |
| 4846 | inline else => |x| &x.output_symtab_ctx, |
| 4847 | }; |
| 4848 | ctx.ilocal = nlocals + 1; |
| 4849 | ctx.iglobal = nglobals + 1; |
| 4850 | try file_ptr.updateSymtabSize(self); |
| 4851 | nlocals += ctx.nlocals; |
| 4852 | nglobals += ctx.nglobals; |
| 4853 | strsize += ctx.strsize; |
| 4505 | 4854 | } |
| 4506 | 4855 | |
| 4507 | 4856 | if (self.zig_got_section_index) |_| { |
| 4857 | self.zig_got.output_symtab_ctx.ilocal = nlocals + 1; |
| 4508 | 4858 | self.zig_got.updateSymtabSize(self); |
| 4509 | | sizes.add(self.zig_got.output_symtab_size); |
| 4859 | nlocals += self.zig_got.output_symtab_ctx.nlocals; |
| 4860 | strsize += self.zig_got.output_symtab_ctx.strsize; |
| 4510 | 4861 | } |
| 4511 | 4862 | |
| 4512 | 4863 | if (self.got_section_index) |_| { |
| 4864 | self.got.output_symtab_ctx.ilocal = nlocals + 1; |
| 4513 | 4865 | self.got.updateSymtabSize(self); |
| 4514 | | sizes.add(self.got.output_symtab_size); |
| 4866 | nlocals += self.got.output_symtab_ctx.nlocals; |
| 4867 | strsize += self.got.output_symtab_ctx.strsize; |
| 4515 | 4868 | } |
| 4516 | 4869 | |
| 4517 | 4870 | if (self.plt_section_index) |_| { |
| 4871 | self.plt.output_symtab_ctx.ilocal = nlocals + 1; |
| 4518 | 4872 | self.plt.updateSymtabSize(self); |
| 4519 | | sizes.add(self.plt.output_symtab_size); |
| 4873 | nlocals += self.plt.output_symtab_ctx.nlocals; |
| 4874 | strsize += self.plt.output_symtab_ctx.strsize; |
| 4520 | 4875 | } |
| 4521 | 4876 | |
| 4522 | 4877 | if (self.plt_got_section_index) |_| { |
| 4878 | self.plt_got.output_symtab_ctx.ilocal = nlocals + 1; |
| 4523 | 4879 | self.plt_got.updateSymtabSize(self); |
| 4524 | | sizes.add(self.plt_got.output_symtab_size); |
| 4880 | nlocals += self.plt_got.output_symtab_ctx.nlocals; |
| 4881 | strsize += self.plt_got.output_symtab_ctx.strsize; |
| 4525 | 4882 | } |
| 4526 | 4883 | |
| 4527 | | if (self.linker_defined_index) |index| { |
| 4884 | for (files.items) |index| { |
| 4528 | 4885 | const file_ptr = self.file(index).?; |
| 4529 | | file_ptr.updateSymtabSize(self); |
| 4530 | | sizes.add(file_ptr.linker_defined.output_symtab_size); |
| 4886 | const ctx = switch (file_ptr) { |
| 4887 | inline else => |x| &x.output_symtab_ctx, |
| 4888 | }; |
| 4889 | ctx.iglobal += nlocals; |
| 4531 | 4890 | } |
| 4532 | 4891 | |
| 4533 | 4892 | const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?]; |
| 4534 | | symtab_shdr.sh_info = sizes.nlocals + 1; |
| 4535 | | symtab_shdr.sh_link = self.strtab_section_index.?; |
| 4536 | | |
| 4537 | | const sym_size: u64 = switch (self.ptr_width) { |
| 4538 | | .p32 => @sizeOf(elf.Elf32_Sym), |
| 4539 | | .p64 => @sizeOf(elf.Elf64_Sym), |
| 4540 | | }; |
| 4541 | | const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; |
| 4542 | | symtab_shdr.sh_size = needed_size; |
| 4543 | | |
| 4544 | | const strtab = &self.shdrs.items[self.strtab_section_index.?]; |
| 4545 | | strtab.sh_size = sizes.strsize + 1; |
| 4546 | | } |
| 4547 | | |
| 4548 | | fn updateSymtabSizeObject(self: *Elf, zig_object: *ZigObject) void { |
| 4549 | | zig_object.asFile().updateSymtabSize(self); |
| 4550 | | const sizes = zig_object.output_symtab_size; |
| 4551 | | |
| 4552 | | const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?]; |
| 4553 | | symtab_shdr.sh_info = sizes.nlocals + 1; |
| 4893 | symtab_shdr.sh_info = nlocals + 1; |
| 4554 | 4894 | symtab_shdr.sh_link = self.strtab_section_index.?; |
| 4555 | 4895 | |
| 4556 | 4896 | const sym_size: u64 = switch (self.ptr_width) { |
| 4557 | 4897 | .p32 => @sizeOf(elf.Elf32_Sym), |
| 4558 | 4898 | .p64 => @sizeOf(elf.Elf64_Sym), |
| 4559 | 4899 | }; |
| 4560 | | const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size; |
| 4900 | const needed_size = (nlocals + nglobals + 1) * sym_size; |
| 4561 | 4901 | symtab_shdr.sh_size = needed_size; |
| 4562 | 4902 | |
| 4563 | 4903 | const strtab = &self.shdrs.items[self.strtab_section_index.?]; |
| 4564 | | strtab.sh_size = sizes.strsize + 1; |
| 4904 | strtab.sh_size = strsize + 1; |
| 4565 | 4905 | } |
| 4566 | 4906 | |
| 4567 | 4907 | fn writeSyntheticSections(self: *Elf) !void { |
| 4568 | 4908 | const gpa = self.base.allocator; |
| 4569 | 4909 | |
| 4570 | | if (self.zigObjectPtr()) |zig_object| { |
| 4571 | | try zig_object.writeRelaSections(self); |
| 4572 | | } |
| 4573 | | |
| 4574 | 4910 | if (self.interp_section_index) |shndx| { |
| 4575 | 4911 | const shdr = self.shdrs.items[shndx]; |
| 4576 | 4912 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| ... | ... | @@ -4698,9 +5034,97 @@ fn writeSyntheticSections(self: *Elf) !void { |
| 4698 | 5034 | try self.writeShStrtab(); |
| 4699 | 5035 | } |
| 4700 | 5036 | |
| 5037 | fn writeSyntheticSectionsObject(self: *Elf) !void { |
| 5038 | const gpa = self.base.allocator; |
| 5039 | |
| 5040 | for (self.output_rela_sections.values()) |sec| { |
| 5041 | if (sec.atom_list.items.len == 0) continue; |
| 5042 | |
| 5043 | const shdr = self.shdrs.items[sec.shndx]; |
| 5044 | |
| 5045 | const num_relocs = math.cast(usize, @divExact(shdr.sh_size, shdr.sh_entsize)) orelse |
| 5046 | return error.Overflow; |
| 5047 | var relocs = try std.ArrayList(elf.Elf64_Rela).initCapacity(gpa, num_relocs); |
| 5048 | defer relocs.deinit(); |
| 5049 | |
| 5050 | for (sec.atom_list.items) |atom_index| { |
| 5051 | const atom_ptr = self.atom(atom_index) orelse continue; |
| 5052 | if (!atom_ptr.flags.alive) continue; |
| 5053 | try atom_ptr.writeRelocs(self, &relocs); |
| 5054 | } |
| 5055 | assert(relocs.items.len == num_relocs); |
| 5056 | |
| 5057 | const SortRelocs = struct { |
| 5058 | pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool { |
| 5059 | _ = ctx; |
| 5060 | return lhs.r_offset < rhs.r_offset; |
| 5061 | } |
| 5062 | }; |
| 5063 | |
| 5064 | mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan); |
| 5065 | |
| 5066 | log.debug("writing {s} from 0x{x} to 0x{x}", .{ |
| 5067 | self.getShString(shdr.sh_name), |
| 5068 | shdr.sh_offset, |
| 5069 | shdr.sh_offset + shdr.sh_size, |
| 5070 | }); |
| 5071 | |
| 5072 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset); |
| 5073 | } |
| 5074 | |
| 5075 | if (self.eh_frame_section_index) |shndx| { |
| 5076 | const shdr = self.shdrs.items[shndx]; |
| 5077 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 5078 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 5079 | defer buffer.deinit(); |
| 5080 | try eh_frame.writeEhFrameObject(self, buffer.writer()); |
| 5081 | log.debug("writing .eh_frame from 0x{x} to 0x{x}", .{ |
| 5082 | shdr.sh_offset, |
| 5083 | shdr.sh_offset + shdr.sh_size, |
| 5084 | }); |
| 5085 | assert(buffer.items.len == sh_size); |
| 5086 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 5087 | } |
| 5088 | if (self.eh_frame_rela_section_index) |shndx| { |
| 5089 | const shdr = self.shdrs.items[shndx]; |
| 5090 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 5091 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 5092 | defer buffer.deinit(); |
| 5093 | try eh_frame.writeEhFrameRelocs(self, buffer.writer()); |
| 5094 | assert(buffer.items.len == sh_size); |
| 5095 | log.debug("writing .rela.eh_frame from 0x{x} to 0x{x}", .{ |
| 5096 | shdr.sh_offset, |
| 5097 | shdr.sh_offset + shdr.sh_size, |
| 5098 | }); |
| 5099 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 5100 | } |
| 5101 | |
| 5102 | try self.writeComdatGroups(); |
| 5103 | try self.writeSymtab(); |
| 5104 | try self.writeShStrtab(); |
| 5105 | } |
| 5106 | |
| 5107 | fn writeComdatGroups(self: *Elf) !void { |
| 5108 | const gpa = self.base.allocator; |
| 5109 | for (self.comdat_group_sections.items) |cgs| { |
| 5110 | const shdr = self.shdrs.items[cgs.shndx]; |
| 5111 | const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; |
| 5112 | var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size); |
| 5113 | defer buffer.deinit(); |
| 5114 | try cgs.write(self, buffer.writer()); |
| 5115 | assert(buffer.items.len == sh_size); |
| 5116 | log.debug("writing COMDAT group from 0x{x} to 0x{x}", .{ |
| 5117 | shdr.sh_offset, |
| 5118 | shdr.sh_offset + shdr.sh_size, |
| 5119 | }); |
| 5120 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); |
| 5121 | } |
| 5122 | } |
| 5123 | |
| 4701 | 5124 | fn writeShStrtab(self: *Elf) !void { |
| 4702 | 5125 | if (self.shstrtab_section_index) |index| { |
| 4703 | 5126 | const shdr = self.shdrs.items[index]; |
| 5127 | log.debug("writing .shstrtab from 0x{x} to 0x{x}", .{ shdr.sh_offset, shdr.sh_offset + shdr.sh_size }); |
| 4704 | 5128 | try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset); |
| 4705 | 5129 | } |
| 4706 | 5130 | } |
| ... | ... | @@ -4715,67 +5139,55 @@ fn writeSymtab(self: *Elf) !void { |
| 4715 | 5139 | }; |
| 4716 | 5140 | const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow; |
| 4717 | 5141 | |
| 4718 | | log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset }); |
| 5142 | log.debug("writing {d} symbols in .symtab from 0x{x} to 0x{x}", .{ |
| 5143 | nsyms, |
| 5144 | symtab_shdr.sh_offset, |
| 5145 | symtab_shdr.sh_offset + symtab_shdr.sh_size, |
| 5146 | }); |
| 5147 | log.debug("writing .strtab from 0x{x} to 0x{x}", .{ |
| 5148 | strtab_shdr.sh_offset, |
| 5149 | strtab_shdr.sh_offset + strtab_shdr.sh_size, |
| 5150 | }); |
| 4719 | 5151 | |
| 4720 | 5152 | try self.symtab.resize(gpa, nsyms); |
| 4721 | 5153 | const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow; |
| 4722 | 5154 | try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size); |
| 4723 | 5155 | |
| 4724 | | const Ctx = struct { |
| 4725 | | ilocal: usize, |
| 4726 | | iglobal: usize, |
| 4727 | | |
| 4728 | | fn incr(this: *@This(), ss: SymtabSize) void { |
| 4729 | | this.ilocal += ss.nlocals; |
| 4730 | | this.iglobal += ss.nglobals; |
| 4731 | | } |
| 4732 | | }; |
| 4733 | | var ctx: Ctx = .{ |
| 4734 | | .ilocal = 1, |
| 4735 | | .iglobal = symtab_shdr.sh_info, |
| 4736 | | }; |
| 5156 | self.writeSectionSymbols(); |
| 4737 | 5157 | |
| 4738 | 5158 | if (self.zigObjectPtr()) |zig_object| { |
| 4739 | | zig_object.asFile().writeSymtab(self, ctx); |
| 4740 | | ctx.incr(zig_object.output_symtab_size); |
| 5159 | zig_object.asFile().writeSymtab(self); |
| 4741 | 5160 | } |
| 4742 | 5161 | |
| 4743 | 5162 | for (self.objects.items) |index| { |
| 4744 | 5163 | const file_ptr = self.file(index).?; |
| 4745 | | file_ptr.writeSymtab(self, ctx); |
| 4746 | | ctx.incr(file_ptr.object.output_symtab_size); |
| 5164 | file_ptr.writeSymtab(self); |
| 4747 | 5165 | } |
| 4748 | 5166 | |
| 4749 | 5167 | for (self.shared_objects.items) |index| { |
| 4750 | 5168 | const file_ptr = self.file(index).?; |
| 4751 | | file_ptr.writeSymtab(self, ctx); |
| 4752 | | ctx.incr(file_ptr.shared_object.output_symtab_size); |
| 5169 | file_ptr.writeSymtab(self); |
| 4753 | 5170 | } |
| 4754 | 5171 | |
| 4755 | 5172 | if (self.zig_got_section_index) |_| { |
| 4756 | | self.zig_got.writeSymtab(self, ctx); |
| 4757 | | ctx.incr(self.zig_got.output_symtab_size); |
| 5173 | self.zig_got.writeSymtab(self); |
| 4758 | 5174 | } |
| 4759 | 5175 | |
| 4760 | 5176 | if (self.got_section_index) |_| { |
| 4761 | | self.got.writeSymtab(self, ctx); |
| 4762 | | ctx.incr(self.got.output_symtab_size); |
| 5177 | self.got.writeSymtab(self); |
| 4763 | 5178 | } |
| 4764 | 5179 | |
| 4765 | 5180 | if (self.plt_section_index) |_| { |
| 4766 | | self.plt.writeSymtab(self, ctx); |
| 4767 | | ctx.incr(self.plt.output_symtab_size); |
| 5181 | self.plt.writeSymtab(self); |
| 4768 | 5182 | } |
| 4769 | 5183 | |
| 4770 | 5184 | if (self.plt_got_section_index) |_| { |
| 4771 | | self.plt_got.writeSymtab(self, ctx); |
| 4772 | | ctx.incr(self.plt_got.output_symtab_size); |
| 5185 | self.plt_got.writeSymtab(self); |
| 4773 | 5186 | } |
| 4774 | 5187 | |
| 4775 | 5188 | if (self.linker_defined_index) |index| { |
| 4776 | 5189 | const file_ptr = self.file(index).?; |
| 4777 | | file_ptr.writeSymtab(self, ctx); |
| 4778 | | ctx.incr(file_ptr.linker_defined.output_symtab_size); |
| 5190 | file_ptr.writeSymtab(self); |
| 4779 | 5191 | } |
| 4780 | 5192 | |
| 4781 | 5193 | const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); |
| ... | ... | @@ -4808,52 +5220,42 @@ fn writeSymtab(self: *Elf) !void { |
| 4808 | 5220 | try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset); |
| 4809 | 5221 | } |
| 4810 | 5222 | |
| 4811 | | fn writeSymtabObject(self: *Elf, zig_object: *ZigObject) !void { |
| 4812 | | const gpa = self.base.allocator; |
| 4813 | | const symtab_shdr = self.shdrs.items[self.symtab_section_index.?]; |
| 4814 | | const strtab_shdr = self.shdrs.items[self.strtab_section_index.?]; |
| 4815 | | const sym_size: u64 = switch (self.ptr_width) { |
| 4816 | | .p32 => @sizeOf(elf.Elf32_Sym), |
| 4817 | | .p64 => @sizeOf(elf.Elf64_Sym), |
| 4818 | | }; |
| 4819 | | const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow; |
| 4820 | | |
| 4821 | | log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset }); |
| 4822 | | |
| 4823 | | try self.symtab.resize(gpa, nsyms); |
| 4824 | | const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow; |
| 4825 | | try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size); |
| 4826 | | |
| 4827 | | zig_object.asFile().writeSymtab(self, .{ .ilocal = 1, .iglobal = symtab_shdr.sh_info }); |
| 4828 | | |
| 4829 | | const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); |
| 4830 | | switch (self.ptr_width) { |
| 4831 | | .p32 => { |
| 4832 | | const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len); |
| 4833 | | defer gpa.free(buf); |
| 5223 | fn writeSectionSymbols(self: *Elf) void { |
| 5224 | var ilocal: u32 = 1; |
| 5225 | for (self.output_sections.keys()) |shndx| { |
| 5226 | const shdr = self.shdrs.items[shndx]; |
| 5227 | const out_sym = &self.symtab.items[ilocal]; |
| 5228 | out_sym.* = .{ |
| 5229 | .st_name = 0, |
| 5230 | .st_value = shdr.sh_addr, |
| 5231 | .st_info = elf.STT_SECTION, |
| 5232 | .st_shndx = @intCast(shndx), |
| 5233 | .st_size = 0, |
| 5234 | .st_other = 0, |
| 5235 | }; |
| 5236 | ilocal += 1; |
| 5237 | } |
| 4834 | 5238 | |
| 4835 | | for (buf, self.symtab.items) |*out, sym| { |
| 4836 | | out.* = .{ |
| 4837 | | .st_name = sym.st_name, |
| 4838 | | .st_info = sym.st_info, |
| 4839 | | .st_other = sym.st_other, |
| 4840 | | .st_shndx = sym.st_shndx, |
| 4841 | | .st_value = @as(u32, @intCast(sym.st_value)), |
| 4842 | | .st_size = @as(u32, @intCast(sym.st_size)), |
| 4843 | | }; |
| 4844 | | if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out); |
| 4845 | | } |
| 4846 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset); |
| 4847 | | }, |
| 4848 | | .p64 => { |
| 4849 | | if (foreign_endian) { |
| 4850 | | for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym); |
| 4851 | | } |
| 4852 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset); |
| 4853 | | }, |
| 5239 | if (self.eh_frame_section_index) |shndx| { |
| 5240 | const shdr = self.shdrs.items[shndx]; |
| 5241 | const out_sym = &self.symtab.items[ilocal]; |
| 5242 | out_sym.* = .{ |
| 5243 | .st_name = 0, |
| 5244 | .st_value = shdr.sh_addr, |
| 5245 | .st_info = elf.STT_SECTION, |
| 5246 | .st_shndx = @intCast(shndx), |
| 5247 | .st_size = 0, |
| 5248 | .st_other = 0, |
| 5249 | }; |
| 5250 | ilocal += 1; |
| 4854 | 5251 | } |
| 5252 | } |
| 4855 | 5253 | |
| 4856 | | try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset); |
| 5254 | pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { |
| 5255 | if (self.eh_frame_section_index) |index| { |
| 5256 | if (index == shndx) return @intCast(self.output_sections.keys().len + 1); |
| 5257 | } |
| 5258 | return @intCast(self.output_sections.getIndex(shndx).? + 1); |
| 4857 | 5259 | } |
| 4858 | 5260 | |
| 4859 | 5261 | /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF. |
| ... | ... | @@ -5707,13 +6109,69 @@ fn formatShdr( |
| 5707 | 6109 | _ = options; |
| 5708 | 6110 | _ = unused_fmt_string; |
| 5709 | 6111 | const shdr = ctx.shdr; |
| 5710 | | try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{ |
| 6112 | try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : flags({})", .{ |
| 5711 | 6113 | ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset, |
| 5712 | 6114 | shdr.sh_addr, shdr.sh_addralign, |
| 5713 | | shdr.sh_size, |
| 6115 | shdr.sh_size, fmtShdrFlags(shdr.sh_flags), |
| 5714 | 6116 | }); |
| 5715 | 6117 | } |
| 5716 | 6118 | |
| 6119 | pub fn fmtShdrFlags(sh_flags: u64) std.fmt.Formatter(formatShdrFlags) { |
| 6120 | return .{ .data = sh_flags }; |
| 6121 | } |
| 6122 | |
| 6123 | fn formatShdrFlags( |
| 6124 | sh_flags: u64, |
| 6125 | comptime unused_fmt_string: []const u8, |
| 6126 | options: std.fmt.FormatOptions, |
| 6127 | writer: anytype, |
| 6128 | ) !void { |
| 6129 | _ = unused_fmt_string; |
| 6130 | _ = options; |
| 6131 | if (elf.SHF_WRITE & sh_flags != 0) { |
| 6132 | try writer.writeAll("W"); |
| 6133 | } |
| 6134 | if (elf.SHF_ALLOC & sh_flags != 0) { |
| 6135 | try writer.writeAll("A"); |
| 6136 | } |
| 6137 | if (elf.SHF_EXECINSTR & sh_flags != 0) { |
| 6138 | try writer.writeAll("X"); |
| 6139 | } |
| 6140 | if (elf.SHF_MERGE & sh_flags != 0) { |
| 6141 | try writer.writeAll("M"); |
| 6142 | } |
| 6143 | if (elf.SHF_STRINGS & sh_flags != 0) { |
| 6144 | try writer.writeAll("S"); |
| 6145 | } |
| 6146 | if (elf.SHF_INFO_LINK & sh_flags != 0) { |
| 6147 | try writer.writeAll("I"); |
| 6148 | } |
| 6149 | if (elf.SHF_LINK_ORDER & sh_flags != 0) { |
| 6150 | try writer.writeAll("L"); |
| 6151 | } |
| 6152 | if (elf.SHF_EXCLUDE & sh_flags != 0) { |
| 6153 | try writer.writeAll("E"); |
| 6154 | } |
| 6155 | if (elf.SHF_COMPRESSED & sh_flags != 0) { |
| 6156 | try writer.writeAll("C"); |
| 6157 | } |
| 6158 | if (elf.SHF_GROUP & sh_flags != 0) { |
| 6159 | try writer.writeAll("G"); |
| 6160 | } |
| 6161 | if (elf.SHF_OS_NONCONFORMING & sh_flags != 0) { |
| 6162 | try writer.writeAll("O"); |
| 6163 | } |
| 6164 | if (elf.SHF_TLS & sh_flags != 0) { |
| 6165 | try writer.writeAll("T"); |
| 6166 | } |
| 6167 | if (elf.SHF_X86_64_LARGE & sh_flags != 0) { |
| 6168 | try writer.writeAll("l"); |
| 6169 | } |
| 6170 | if (elf.SHF_MIPS_ADDR & sh_flags != 0 or elf.SHF_ARM_PURECODE & sh_flags != 0) { |
| 6171 | try writer.writeAll("p"); |
| 6172 | } |
| 6173 | } |
| 6174 | |
| 5717 | 6175 | const FormatPhdrCtx = struct { |
| 5718 | 6176 | elf_file: *Elf, |
| 5719 | 6177 | phdr: elf.Elf64_Phdr, |
| ... | ... | @@ -5813,9 +6271,14 @@ fn fmtDumpState( |
| 5813 | 6271 | try writer.print("{}\n", .{self.got.fmt(self)}); |
| 5814 | 6272 | try writer.print("{}\n", .{self.zig_got.fmt(self)}); |
| 5815 | 6273 | |
| 5816 | | try writer.writeAll("Output shdrs\n"); |
| 6274 | try writer.writeAll("Output COMDAT groups\n"); |
| 6275 | for (self.comdat_group_sections.items) |cg| { |
| 6276 | try writer.print(" shdr({d}) : COMDAT({d})\n", .{ cg.shndx, cg.cg_index }); |
| 6277 | } |
| 6278 | |
| 6279 | try writer.writeAll("\nOutput shdrs\n"); |
| 5817 | 6280 | for (self.shdrs.items, 0..) |shdr, shndx| { |
| 5818 | | try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{ |
| 6281 | try writer.print(" shdr({d}) : phdr({?d}) : {}\n", .{ |
| 5819 | 6282 | shndx, |
| 5820 | 6283 | self.phdr_to_shdr_table.get(@intCast(shndx)), |
| 5821 | 6284 | self.fmtShdr(shdr), |
| ... | ... | @@ -5823,7 +6286,7 @@ fn fmtDumpState( |
| 5823 | 6286 | } |
| 5824 | 6287 | try writer.writeAll("\nOutput phdrs\n"); |
| 5825 | 6288 | for (self.phdrs.items, 0..) |phdr, phndx| { |
| 5826 | | try writer.print("phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) }); |
| 6289 | try writer.print(" phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) }); |
| 5827 | 6290 | } |
| 5828 | 6291 | } |
| 5829 | 6292 | |
| ... | ... | @@ -5882,16 +6345,12 @@ pub const ComdatGroup = struct { |
| 5882 | 6345 | pub const Index = u32; |
| 5883 | 6346 | }; |
| 5884 | 6347 | |
| 5885 | | pub const SymtabSize = struct { |
| 6348 | pub const SymtabCtx = struct { |
| 6349 | ilocal: u32 = 0, |
| 6350 | iglobal: u32 = 0, |
| 5886 | 6351 | nlocals: u32 = 0, |
| 5887 | 6352 | nglobals: u32 = 0, |
| 5888 | 6353 | strsize: u32 = 0, |
| 5889 | | |
| 5890 | | fn add(ss: *SymtabSize, other: SymtabSize) void { |
| 5891 | | ss.nlocals += other.nlocals; |
| 5892 | | ss.nglobals += other.nglobals; |
| 5893 | | ss.strsize += other.strsize; |
| 5894 | | } |
| 5895 | 6354 | }; |
| 5896 | 6355 | |
| 5897 | 6356 | pub const null_sym = elf.Elf64_Sym{ |
| ... | ... | @@ -5942,8 +6401,13 @@ const LastAtomAndFreeList = struct { |
| 5942 | 6401 | /// by 1 byte. It will then have -1 overcapacity. |
| 5943 | 6402 | free_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 5944 | 6403 | }; |
| 6404 | const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u32, LastAtomAndFreeList); |
| 5945 | 6405 | |
| 5946 | | const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList); |
| 6406 | const RelaSection = struct { |
| 6407 | shndx: u32, |
| 6408 | atom_list: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 6409 | }; |
| 6410 | const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection); |
| 5947 | 6411 | |
| 5948 | 6412 | pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1; |
| 5949 | 6413 | pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2; |
| ... | ... | @@ -5976,6 +6440,7 @@ const Archive = @import("Elf/Archive.zig"); |
| 5976 | 6440 | pub const Atom = @import("Elf/Atom.zig"); |
| 5977 | 6441 | const Cache = std.Build.Cache; |
| 5978 | 6442 | const Compilation = @import("../Compilation.zig"); |
| 6443 | const ComdatGroupSection = synthetic_sections.ComdatGroupSection; |
| 5979 | 6444 | const CopyRelSection = synthetic_sections.CopyRelSection; |
| 5980 | 6445 | const DynamicSection = synthetic_sections.DynamicSection; |
| 5981 | 6446 | const DynsymSection = synthetic_sections.DynsymSection; |