| ... | @@ -92,6 +92,8 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { | ... | @@ -92,6 +92,8 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| 92 | }), | 92 | }), |
| 93 | pending_uavs: std.ArrayList(Node.UavMapIndex), | 93 | pending_uavs: std.ArrayList(Node.UavMapIndex), |
| 94 | relocs: std.ArrayList(Reloc), | 94 | relocs: std.ArrayList(Reloc), |
| | 95 | /// Index matches the index into `shdrs`. |
| | 96 | section_by_name: std.array_hash_map.Auto(String(.shstrtab), void), |
| 95 | | 97 | |
| 96 | /// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation | 98 | /// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation |
| 97 | /// entries which target that symbol must be updated to reference the correct symbol index. | 99 | /// entries which target that symbol must be updated to reference the correct symbol index. |
| ... | @@ -361,11 +363,10 @@ const Section = struct { | ... | @@ -361,11 +363,10 @@ const Section = struct { |
| 361 | return &elf.shdrs.items[@intFromEnum(s)]; | 363 | return &elf.shdrs.items[@intFromEnum(s)]; |
| 362 | } | 364 | } |
| 363 | | 365 | |
| 364 | fn name(s: Index, elf: *Elf) [:0]const u8 { | 366 | fn name(s: Index, elf: *Elf) String(.shstrtab) { |
| 365 | const str: String(.shstrtab) = switch (elf.shdrPtr(s)) { | 367 | return switch (elf.shdrPtr(s)) { |
| 366 | inline else => |shdr| @enumFromInt(elf.targetLoad(&shdr.name)), | 368 | inline else => |shdr| @enumFromInt(elf.targetLoad(&shdr.name)), |
| 367 | }; | 369 | }; |
| 368 | return str.slice(elf); | | |
| 369 | } | 370 | } |
| 370 | | 371 | |
| 371 | fn vaddr(s: Index, elf: *Elf) u64 { | 372 | fn vaddr(s: Index, elf: *Elf) u64 { |
| ... | @@ -1372,7 +1373,7 @@ pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) !link.File.SymbolId | ... | @@ -1372,7 +1373,7 @@ pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) !link.File.SymbolId |
| 1372 | return elf.externSymbol(.{ | 1373 | return elf.externSymbol(.{ |
| 1373 | .name = @"extern".name.toSlice(ip), | 1374 | .name = @"extern".name.toSlice(ip), |
| 1374 | .lib_name = @"extern".lib_name.toSlice(ip), | 1375 | .lib_name = @"extern".lib_name.toSlice(ip), |
| 1375 | .type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded), | 1376 | .type = elf.navType(nav.resolved.?), |
| 1376 | .linkage = @"extern".linkage, | 1377 | .linkage = @"extern".linkage, |
| 1377 | .visibility = @"extern".visibility, | 1378 | .visibility = @"extern".visibility, |
| 1378 | }); | 1379 | }); |
| ... | @@ -1956,6 +1957,7 @@ fn create( | ... | @@ -1956,6 +1957,7 @@ fn create( |
| 1956 | }), | 1957 | }), |
| 1957 | .pending_uavs = .empty, | 1958 | .pending_uavs = .empty, |
| 1958 | .relocs = .empty, | 1959 | .relocs = .empty, |
| | 1960 | .section_by_name = .empty, |
| 1959 | .changed_symtab_index = .empty, | 1961 | .changed_symtab_index = .empty, |
| 1960 | .const_prog_node = .none, | 1962 | .const_prog_node = .none, |
| 1961 | .synth_prog_node = .none, | 1963 | .synth_prog_node = .none, |
| ... | @@ -1992,6 +1994,7 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -1992,6 +1994,7 @@ pub fn deinit(elf: *Elf) void { |
| 1992 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); | 1994 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| 1993 | elf.pending_uavs.deinit(gpa); | 1995 | elf.pending_uavs.deinit(gpa); |
| 1994 | elf.relocs.deinit(gpa); | 1996 | elf.relocs.deinit(gpa); |
| | 1997 | elf.section_by_name.deinit(gpa); |
| 1995 | elf.changed_symtab_index.deinit(gpa); | 1998 | elf.changed_symtab_index.deinit(gpa); |
| 1996 | elf.* = undefined; | 1999 | elf.* = undefined; |
| 1997 | } | 2000 | } |
| ... | @@ -2561,6 +2564,12 @@ fn initHeaders( | ... | @@ -2561,6 +2564,12 @@ fn initHeaders( |
| 2561 | .addralign = elf.mf.flags.block_size, | 2564 | .addralign = elf.mf.flags.block_size, |
| 2562 | }); | 2565 | }); |
| 2563 | assert(elf.nodes.len == expected_nodes_len); | 2566 | assert(elf.nodes.len == expected_nodes_len); |
| | 2567 | |
| | 2568 | try elf.section_by_name.ensureUnusedCapacity(gpa, elf.shdrs.items.len); |
| | 2569 | for (0..elf.shdrs.items.len) |shndx_raw| { |
| | 2570 | const shndx: Section.Index = @enumFromInt(shndx_raw); |
| | 2571 | elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {}); |
| | 2572 | } |
| 2564 | } | 2573 | } |
| 2565 | | 2574 | |
| 2566 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { | 2575 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { |
| ... | @@ -2810,28 +2819,129 @@ fn dynsymPtr(elf: *Elf, index: u32) SymPtr { | ... | @@ -2810,28 +2819,129 @@ fn dynsymPtr(elf: *Elf, index: u32) SymPtr { |
| 2810 | } | 2819 | } |
| 2811 | } | 2820 | } |
| 2812 | | 2821 | |
| 2813 | fn navType( | 2822 | fn navType(elf: *const Elf, nav_resolved: InternPool.Nav.Resolved) std.elf.STT { |
| 2814 | ip: *const InternPool, | 2823 | const any_non_single_threaded = elf.base.comp.config.any_non_single_threaded; |
| 2815 | nav_resolved: @typeInfo(@FieldType(InternPool.Nav, "resolved")).optional.child, | | |
| 2816 | any_non_single_threaded: bool, | | |
| 2817 | ) std.elf.STT { | | |
| 2818 | return if (any_non_single_threaded and nav_resolved.@"threadlocal") | 2824 | return if (any_non_single_threaded and nav_resolved.@"threadlocal") |
| 2819 | .TLS | 2825 | .TLS |
| 2820 | else if (ip.isFunctionType(nav_resolved.type)) | 2826 | else if (elf.base.comp.zcu.?.intern_pool.isFunctionType(nav_resolved.type)) |
| 2821 | .FUNC | 2827 | .FUNC |
| 2822 | else | 2828 | else |
| 2823 | .OBJECT; | 2829 | .OBJECT; |
| 2824 | } | 2830 | } |
| 2825 | fn namedSection(elf: *const Elf, name: []const u8) ?Section.Index { | 2831 | fn mapInputSection(elf: *Elf, opts: struct { |
| 2826 | if (std.mem.eql(u8, name, ".rodata") or | 2832 | name: []const u8, |
| 2827 | std.mem.startsWith(u8, name, ".rodata.")) return .rodata; | 2833 | flags: std.elf.SHF, |
| 2828 | if (std.mem.eql(u8, name, ".text") or | 2834 | addralign: std.elf.Xword, |
| 2829 | std.mem.startsWith(u8, name, ".text.")) return .text; | 2835 | entsize: std.elf.Xword, |
| 2830 | if (std.mem.eql(u8, name, ".data") or | 2836 | }) !Section.Index { |
| 2831 | std.mem.startsWith(u8, name, ".data.")) return .data; | 2837 | const gpa = elf.base.comp.gpa; |
| 2832 | if (std.mem.eql(u8, name, ".tdata") or | 2838 | if (opts.flags.INFO_LINK or |
| 2833 | std.mem.startsWith(u8, name, ".tdata.")) return elf.shndx.tdata; | 2839 | opts.flags.LINK_ORDER or |
| 2834 | return null; | 2840 | opts.flags.OS_NONCONFORMING or |
| | 2841 | (opts.flags.EXECINSTR and opts.flags.WRITE) or |
| | 2842 | (opts.flags.EXECINSTR and opts.flags.TLS)) |
| | 2843 | { |
| | 2844 | return error.UnsupportedSectionFlags; |
| | 2845 | } |
| | 2846 | if (opts.flags.TLS and elf.ni.tls == .none) { |
| | 2847 | assert(!elf.base.comp.config.any_non_single_threaded); |
| | 2848 | return error.TlsSectionUnavailable; |
| | 2849 | } |
| | 2850 | const name: []const u8 = switch (elf.ehdrField(.type)) { |
| | 2851 | .NONE, .CORE, _ => unreachable, |
| | 2852 | .REL => opts.name, |
| | 2853 | .EXEC, .DYN => name: { |
| | 2854 | if (std.mem.startsWith(u8, opts.name, ".text.")) break :name ".text"; |
| | 2855 | if (std.mem.startsWith(u8, opts.name, ".rodata.")) break :name ".rodata"; |
| | 2856 | if (std.mem.startsWith(u8, opts.name, ".data.")) break :name ".data"; |
| | 2857 | if (std.mem.startsWith(u8, opts.name, ".data.rel.ro.")) break :name ".data.rel.ro"; |
| | 2858 | if (std.mem.startsWith(u8, opts.name, ".tdata.")) break :name ".tdata"; |
| | 2859 | if (std.mem.startsWith(u8, opts.name, ".gcc_except_table.")) break :name ".gcc_except_table"; |
| | 2860 | // TODO: actually generate a bss section! |
| | 2861 | if (std.mem.eql(u8, opts.name, ".bss")) break :name ".data"; |
| | 2862 | if (std.mem.startsWith(u8, opts.name, ".bss.")) break :name ".data"; |
| | 2863 | // TODO: actually generate a tbss section! |
| | 2864 | if (std.mem.eql(u8, opts.name, ".tbss")) break :name ".tdata"; |
| | 2865 | if (std.mem.startsWith(u8, opts.name, ".tbss.")) break :name ".tdata"; |
| | 2866 | break :name opts.name; |
| | 2867 | }, |
| | 2868 | }; |
| | 2869 | const existing_shndx: Section.Index = existing: { |
| | 2870 | const name_shstrtab = try elf.string(.shstrtab, name); |
| | 2871 | const gop = try elf.section_by_name.getOrPut(gpa, name_shstrtab); |
| | 2872 | if (gop.found_existing) { |
| | 2873 | break :existing @enumFromInt(gop.index); |
| | 2874 | } |
| | 2875 | errdefer assert(elf.section_by_name.pop().?.key == name_shstrtab); |
| | 2876 | const parent_node: MappedFile.Node.Index = parent: { |
| | 2877 | if (!opts.flags.ALLOC) break :parent elf.ni.file; |
| | 2878 | if (opts.flags.EXECINSTR) break :parent elf.ni.text; |
| | 2879 | if (opts.flags.TLS) break :parent elf.ni.tls; |
| | 2880 | if (opts.flags.WRITE) break :parent elf.ni.data; |
| | 2881 | break :parent elf.ni.rodata; |
| | 2882 | }; |
| | 2883 | assert(gop.index == elf.shdrs.items.len); |
| | 2884 | return elf.addSection(parent_node, .{ |
| | 2885 | .name = name, |
| | 2886 | .type = .NULL, // because initial size is 0 |
| | 2887 | .flags = flags: { |
| | 2888 | // We need to decompress the section for linking. |
| | 2889 | var flags = opts.flags; |
| | 2890 | flags.COMPRESSED = false; |
| | 2891 | break :flags flags; |
| | 2892 | }, |
| | 2893 | .node_align = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| | 2894 | usize, |
| | 2895 | @intCast(@max(opts.addralign, 1)), |
| | 2896 | )), |
| | 2897 | .entsize = std.math.lossyCast(u32, opts.entsize), |
| | 2898 | }); |
| | 2899 | }; |
| | 2900 | // Validate that the input is compatible with this section... |
| | 2901 | switch (elf.shdrPtr(existing_shndx)) { |
| | 2902 | inline else => |shdr| { |
| | 2903 | const cur_flags = elf.targetLoad(&shdr.flags).shf; |
| | 2904 | if (cur_flags.EXECINSTR != opts.flags.EXECINSTR or |
| | 2905 | cur_flags.WRITE != opts.flags.WRITE or |
| | 2906 | cur_flags.TLS != opts.flags.TLS) |
| | 2907 | { |
| | 2908 | return error.SectionFlagsConflict; |
| | 2909 | } |
| | 2910 | |
| | 2911 | switch (elf.targetLoad(&shdr.type)) { |
| | 2912 | .NULL, .PROGBITS => {}, |
| | 2913 | else => return error.SectionTypeConflict, |
| | 2914 | } |
| | 2915 | }, |
| | 2916 | } |
| | 2917 | // ...then realign the section's node if necessary... |
| | 2918 | if (opts.addralign > existing_shndx.get(elf).ni.alignment(&elf.mf).toByteUnits()) { |
| | 2919 | const new_alignment: std.mem.Alignment = .fromByteUnits( |
| | 2920 | std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)), |
| | 2921 | ); |
| | 2922 | try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment); |
| | 2923 | } |
| | 2924 | // ...and update the shdr as needed. |
| | 2925 | switch (elf.shdrPtr(existing_shndx)) { |
| | 2926 | inline else => |shdr| { |
| | 2927 | // Combine the section flags. |
| | 2928 | const cur_flags = elf.targetLoad(&shdr.flags).shf; |
| | 2929 | elf.targetStore(&shdr.flags, .{ .shf = .{ |
| | 2930 | .EXECINSTR = cur_flags.EXECINSTR, |
| | 2931 | .WRITE = cur_flags.WRITE, |
| | 2932 | .TLS = cur_flags.TLS, |
| | 2933 | .ALLOC = cur_flags.ALLOC or opts.flags.ALLOC, |
| | 2934 | .STRINGS = cur_flags.STRINGS and opts.flags.STRINGS, |
| | 2935 | .MERGE = cur_flags.MERGE and opts.flags.MERGE, |
| | 2936 | } }); |
| | 2937 | // Increase addralign to the maximum of the current value and the new value---the node |
| | 2938 | // alignment was already increased above. |
| | 2939 | if (opts.addralign > elf.targetLoad(&shdr.addralign)) { |
| | 2940 | elf.targetStore(&shdr.addralign, @intCast(opts.addralign)); |
| | 2941 | } |
| | 2942 | }, |
| | 2943 | } |
| | 2944 | return existing_shndx; |
| 2835 | } | 2945 | } |
| 2836 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | 2946 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { |
| 2837 | const gpa = zcu.gpa; | 2947 | const gpa = zcu.gpa; |
| ... | @@ -2845,17 +2955,40 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavM | ... | @@ -2845,17 +2955,40 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavM |
| 2845 | const nav_gop = elf.navs.getOrPutAssumeCapacity(nav_index); | 2955 | const nav_gop = elf.navs.getOrPutAssumeCapacity(nav_index); |
| 2846 | const nmi: Node.NavMapIndex = @enumFromInt(nav_gop.index); | 2956 | const nmi: Node.NavMapIndex = @enumFromInt(nav_gop.index); |
| 2847 | if (!nav_gop.found_existing) { | 2957 | if (!nav_gop.found_existing) { |
| 2848 | const sym_type = navType(ip, nav.resolved.?, elf.base.comp.config.any_non_single_threaded); | | |
| 2849 | const shndx: Section.Index = section: { | 2958 | const shndx: Section.Index = section: { |
| 2850 | if (nav.resolved.?.@"linksection".toSlice(ip)) |@"linksection"| { | 2959 | if (nav.resolved.?.@"linksection".toSlice(ip)) |@"linksection"| { |
| 2851 | if (elf.namedSection(@"linksection")) |shndx| break :section shndx; | 2960 | if (elf.mapInputSection(.{ |
| | 2961 | .name = @"linksection", |
| | 2962 | .flags = .{ |
| | 2963 | .ALLOC = true, |
| | 2964 | .EXECINSTR = ip.isFunctionType(nav.resolved.?.type), |
| | 2965 | .WRITE = !nav.resolved.?.@"const", |
| | 2966 | .TLS = elf.base.comp.config.any_non_single_threaded and |
| | 2967 | nav.resolved.?.@"threadlocal", |
| | 2968 | }, |
| | 2969 | .addralign = 1, |
| | 2970 | .entsize = 0, |
| | 2971 | })) |shndx| { |
| | 2972 | break :section shndx; |
| | 2973 | } else |err| switch (err) { |
| | 2974 | error.TlsSectionUnavailable, |
| | 2975 | error.UnsupportedSectionFlags, |
| | 2976 | error.SectionTypeConflict, |
| | 2977 | error.SectionFlagsConflict, |
| | 2978 | => {}, // fall back to default behavior below |
| | 2979 | |
| | 2980 | else => |e| return e, |
| | 2981 | } |
| | 2982 | } |
| | 2983 | if (elf.base.comp.config.any_non_single_threaded and nav.resolved.?.@"threadlocal") { |
| | 2984 | break :section elf.shndx.tdata; |
| | 2985 | } else if (!nav.resolved.?.@"const") { |
| | 2986 | break :section .data; |
| | 2987 | } else if (ip.isFunctionType(nav.resolved.?.type)) { |
| | 2988 | break :section .text; |
| | 2989 | } else { |
| | 2990 | break :section .rodata; |
| 2852 | } | 2991 | } |
| 2853 | break :section switch (sym_type) { | | |
| 2854 | else => unreachable, | | |
| 2855 | .FUNC => .text, | | |
| 2856 | .OBJECT => .data, | | |
| 2857 | .TLS => elf.shndx.tdata, | | |
| 2858 | }; | | |
| 2859 | }; | 2992 | }; |
| 2860 | const alignment: InternPool.Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) { | 2993 | const alignment: InternPool.Alignment = switch (Type.fromInterned(nav.resolved.?.type).zigTypeTag(zcu)) { |
| 2861 | .@"fn" => a: { | 2994 | .@"fn" => a: { |
| ... | @@ -2887,7 +3020,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavM | ... | @@ -2887,7 +3020,7 @@ fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavM |
| 2887 | .name = try elf.string(.strtab, nav.fqn.toSlice(ip)), | 3020 | .name = try elf.string(.strtab, nav.fqn.toSlice(ip)), |
| 2888 | .value = 0, | 3021 | .value = 0, |
| 2889 | .size = 0, | 3022 | .size = 0, |
| 2890 | .type = sym_type, | 3023 | .type = elf.navType(nav.resolved.?), |
| 2891 | .shndx = shndx, | 3024 | .shndx = shndx, |
| 2892 | }), | 3025 | }), |
| 2893 | .first_reloc = .none, | 3026 | .first_reloc = .none, |
| ... | @@ -3131,26 +3264,69 @@ fn loadObject( | ... | @@ -3131,26 +3264,69 @@ fn loadObject( |
| 3131 | node_fixed: bool, | 3264 | node_fixed: bool, |
| 3132 | } = switch (section.shdr.type) { | 3265 | } = switch (section.shdr.type) { |
| 3133 | else => continue, | 3266 | else => continue, |
| 3134 | .PROGBITS => .{ | 3267 | .PROGBITS, .NOBITS => opts: { |
| 3135 | .shndx = elf.namedSection(name) orelse continue, | 3268 | const shndx = elf.mapInputSection(.{ |
| 3136 | .has_file_bits = true, | 3269 | .name = name, |
| 3137 | .node_fixed = false, | 3270 | .flags = section.shdr.flags.shf, |
| 3138 | }, | 3271 | .addralign = section.shdr.addralign, |
| 3139 | .NOBITS => .{ | 3272 | .entsize = section.shdr.entsize, |
| 3140 | .shndx = shndx: { | 3273 | }) catch |err| switch (err) { |
| 3141 | // TODO: actually generate a .bss section. For now, just throw it into `.data`. | 3274 | error.TlsSectionUnavailable => return diags.failParse( |
| 3142 | if (std.mem.eql(u8, name, ".bss") or std.mem.startsWith(u8, name, ".bss.")) { | 3275 | path, |
| 3143 | break :shndx .data; | 3276 | "thread-local storage section '{s}' is incompatible with '-fsingle-threaded'", |
| 3144 | } | 3277 | .{name}, |
| 3145 | if (elf.shndx.tdata != .UNDEF and | 3278 | ), |
| 3146 | (std.mem.eql(u8, name, ".tbss") or std.mem.startsWith(u8, name, ".tbss."))) | 3279 | error.UnsupportedSectionFlags => if (!section.shdr.flags.shf.ALLOC) { |
| 3147 | { | 3280 | // It probably doesn't matter, just skip this section. |
| 3148 | break :shndx elf.shndx.tdata; | 3281 | continue; |
| 3149 | } | 3282 | } else return diags.failParse( |
| | 3283 | path, |
| | 3284 | "unsupported flags for section '{s}'", |
| | 3285 | .{name}, |
| | 3286 | ), |
| | 3287 | error.SectionTypeConflict => if (!section.shdr.flags.shf.ALLOC) { |
| | 3288 | // It probably doesn't matter, just skip this section. |
| | 3289 | continue; |
| | 3290 | } else return diags.failParse( |
| | 3291 | path, |
| | 3292 | "type of section '{s}' conflicts with other inputs", |
| | 3293 | .{name}, |
| | 3294 | ), |
| | 3295 | error.SectionFlagsConflict => if (!section.shdr.flags.shf.ALLOC) { |
| | 3296 | // It probably doesn't matter, just skip this section. |
| | 3297 | continue; |
| | 3298 | } else return diags.failParse( |
| | 3299 | path, |
| | 3300 | "flags of section '{s}' conflict with other inputs", |
| | 3301 | .{name}, |
| | 3302 | ), |
| | 3303 | else => |e| return e, |
| | 3304 | }; |
| | 3305 | if (section.shdr.flags.shf.COMPRESSED) { |
| | 3306 | // SHF_COMPRESSED is only allowed on non-alloc sections. |
| | 3307 | if (section.shdr.flags.shf.ALLOC) return diags.failParse( |
| | 3308 | path, |
| | 3309 | "section '{s}' has conflicting flags SHF_ALLOC and SHF_COMPRESSED", |
| | 3310 | .{name}, |
| | 3311 | ); |
| | 3312 | // TODO: handle compressed input sections. We'll need to set a flag to |
| | 3313 | // indicate that `flushInputSection` needs to decompress the section. |
| | 3314 | // But because this section isn't SHF_ALLOC, it's probably okay to just |
| | 3315 | // skip it for now. |
| 3150 | continue; | 3316 | continue; |
| 3151 | }, | 3317 | } |
| 3152 | .has_file_bits = false, | 3318 | break :opts .{ |
| 3153 | .node_fixed = false, | 3319 | .shndx = shndx, |
| | 3320 | .has_file_bits = section.shdr.type == .PROGBITS, |
| | 3321 | // For well-known sections, we know that it's fine to have e.g. random |
| | 3322 | // padding, so there's no need to make the sections fixed. For custom |
| | 3323 | // sections, however, we do want fixed nodes to avoid padding. |
| | 3324 | .node_fixed = shndx != .text and |
| | 3325 | shndx != .rodata and |
| | 3326 | shndx != .data and |
| | 3327 | shndx != .data_rel_ro and |
| | 3328 | shndx != elf.shndx.tdata, |
| | 3329 | }; |
| 3154 | }, | 3330 | }, |
| 3155 | inline .INIT_ARRAY, .FINI_ARRAY, .PREINIT_ARRAY => |@"type"| .{ | 3331 | inline .INIT_ARRAY, .FINI_ARRAY, .PREINIT_ARRAY => |@"type"| .{ |
| 3156 | .shndx = shndx: { | 3332 | .shndx = shndx: { |
| ... | @@ -3372,11 +3548,17 @@ fn loadObject( | ... | @@ -3372,11 +3548,17 @@ fn loadObject( |
| 3372 | .{rel.info.sym}, | 3548 | .{rel.info.sym}, |
| 3373 | ); | 3549 | ); |
| 3374 | const target = symmap.items[rel.info.sym - 1]; | 3550 | const target = symmap.items[rel.info.sym - 1]; |
| 3375 | if (target == Symbol.Id.null) return diags.failParse( | 3551 | if (target == Symbol.Id.null) { |
| 3376 | path, | 3552 | // If this is not an SHF_ALLOC section, then let's let this |
| 3377 | "unsupported symbol at index {d} required for relocation", | 3553 | // slide for now, because it probably doesn't affect the final |
| 3378 | .{rel.info.sym}, | 3554 | // binary's functionality for this section to be a bit broken. |
| 3379 | ); | 3555 | if (!loc_sec.shdr.flags.shf.ALLOC) continue; |
| | 3556 | return diags.failParse( |
| | 3557 | path, |
| | 3558 | "unsupported symbol at index {d} required for relocation", |
| | 3559 | .{rel.info.sym}, |
| | 3560 | ); |
| | 3561 | } |
| 3380 | elf.addRelocAssumeCapacity( | 3562 | elf.addRelocAssumeCapacity( |
| 3381 | loc_node, | 3563 | loc_node, |
| 3382 | rel.offset - loc_sec.shdr.addr, | 3564 | rel.offset - loc_sec.shdr.addr, |
| ... | @@ -3531,17 +3713,21 @@ fn createInitFiniArraySection( | ... | @@ -3531,17 +3713,21 @@ fn createInitFiniArraySection( |
| 3531 | @"type": std.elf.SHT, | 3713 | @"type": std.elf.SHT, |
| 3532 | ) !void { | 3714 | ) !void { |
| 3533 | assert(shndx.* == .UNDEF); | 3715 | assert(shndx.* == .UNDEF); |
| | 3716 | const gpa = elf.base.comp.gpa; |
| 3534 | const addr_align: std.mem.Alignment = switch (elf.identClass()) { | 3717 | const addr_align: std.mem.Alignment = switch (elf.identClass()) { |
| 3535 | .NONE, _ => unreachable, | 3718 | .NONE, _ => unreachable, |
| 3536 | .@"32" => .@"4", | 3719 | .@"32" => .@"4", |
| 3537 | .@"64" => .@"8", | 3720 | .@"64" => .@"8", |
| 3538 | }; | 3721 | }; |
| | 3722 | assert(elf.section_by_name.count() == elf.shdrs.items.len); |
| | 3723 | try elf.section_by_name.ensureUnusedCapacity(gpa, 1); |
| 3539 | shndx.* = try elf.addSection(elf.ni.data_rel_ro, .{ | 3724 | shndx.* = try elf.addSection(elf.ni.data_rel_ro, .{ |
| 3540 | .name = "." ++ name, | 3725 | .name = "." ++ name, |
| 3541 | .type = @"type", | 3726 | .type = @"type", |
| 3542 | .flags = .{ .WRITE = true, .ALLOC = true }, | 3727 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 3543 | .node_align = addr_align, | 3728 | .node_align = addr_align, |
| 3544 | }); | 3729 | }); |
| | 3730 | elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {}); |
| 3545 | try elf.ensureUnusedSymbolCapacity(2, .maybe_global); | 3731 | try elf.ensureUnusedSymbolCapacity(2, .maybe_global); |
| 3546 | _ = elf.addGlobalSymbolAssumeCapacity(.{ | 3732 | _ = elf.addGlobalSymbolAssumeCapacity(.{ |
| 3547 | .node = shndx.get(elf).ni, | 3733 | .node = shndx.get(elf).ni, |
| ... | @@ -3879,9 +4065,11 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) | ... | @@ -3879,9 +4065,11 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 3879 | var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa); | 4065 | var bfa: std.heap.BufferFirstAllocator = .init(&bfa_buf, gpa); |
| 3880 | const allocator = bfa.allocator(); | 4066 | const allocator = bfa.allocator(); |
| 3881 | | 4067 | |
| 3882 | const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{shndx.name(elf)}); | 4068 | const rela_name = try std.fmt.allocPrint(allocator, ".rela{s}", .{shndx.name(elf).slice(elf)}); |
| 3883 | defer allocator.free(rela_name); | 4069 | defer allocator.free(rela_name); |
| 3884 | | 4070 | |
| | 4071 | assert(elf.section_by_name.count() == elf.shdrs.items.len); |
| | 4072 | try elf.section_by_name.ensureUnusedCapacity(gpa, 1); |
| 3885 | const rela_shndx = try elf.addSection(.none, .{ | 4073 | const rela_shndx = try elf.addSection(.none, .{ |
| 3886 | .name = rela_name, | 4074 | .name = rela_name, |
| 3887 | .type = .RELA, | 4075 | .type = .RELA, |
| ... | @@ -3898,6 +4086,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) | ... | @@ -3898,6 +4086,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 3898 | }, | 4086 | }, |
| 3899 | .node_align = elf.mf.flags.block_size, | 4087 | .node_align = elf.mf.flags.block_size, |
| 3900 | }); | 4088 | }); |
| | 4089 | elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {}); |
| 3901 | shndx.get(elf).rela_shndx = rela_shndx; | 4090 | shndx.get(elf).rela_shndx = rela_shndx; |
| 3902 | } | 4091 | } |
| 3903 | break :rela .{ shndx.get(elf).rela_shndx, len }; | 4092 | break :rela .{ shndx.get(elf).rela_shndx, len }; |
| ... | @@ -4272,7 +4461,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -4272,7 +4461,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 4272 | return comp.link_diags.fail( | 4461 | return comp.link_diags.fail( |
| 4273 | "linker failed to read input section '{s}' from \"{f}{f}\": {t}", | 4462 | "linker failed to read input section '{s}' from \"{f}{f}\": {t}", |
| 4274 | .{ | 4463 | .{ |
| 4275 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf), | 4464 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf), |
| 4276 | ii.path(elf).fmtEscapeString(), | 4465 | ii.path(elf).fmtEscapeString(), |
| 4277 | fmtMemberString(ii.member(elf)), | 4466 | fmtMemberString(ii.member(elf)), |
| 4278 | e, | 4467 | e, |
| ... | @@ -4325,13 +4514,13 @@ fn idleProgNode( | ... | @@ -4325,13 +4514,13 @@ fn idleProgNode( |
| 4325 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | 4514 | var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 4326 | return prog_node.start(name: switch (node) { | 4515 | return prog_node.start(name: switch (node) { |
| 4327 | else => |tag| @tagName(tag), | 4516 | else => |tag| @tagName(tag), |
| 4328 | .section => |shndx| shndx.name(elf), | 4517 | .section => |shndx| shndx.name(elf).slice(elf), |
| 4329 | .input_section => |isi| { | 4518 | .input_section => |isi| { |
| 4330 | const ii = isi.input(elf); | 4519 | const ii = isi.input(elf); |
| 4331 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ | 4520 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ |
| 4332 | ii.path(elf).fmtEscapeString(), | 4521 | ii.path(elf).fmtEscapeString(), |
| 4333 | fmtMemberString(ii.member(elf)), | 4522 | fmtMemberString(ii.member(elf)), |
| 4334 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf), | 4523 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf), |
| 4335 | }) catch &name; | 4524 | }) catch &name; |
| 4336 | }, | 4525 | }, |
| 4337 | .nav => |nmi| { | 4526 | .nav => |nmi| { |
| ... | @@ -4885,7 +5074,7 @@ fn updateExportsInner( | ... | @@ -4885,7 +5074,7 @@ fn updateExportsInner( |
| 4885 | const exported_lsi: Symbol.LocalIndex, const @"type": std.elf.STT = switch (exported) { | 5074 | const exported_lsi: Symbol.LocalIndex, const @"type": std.elf.STT = switch (exported) { |
| 4886 | .nav => |nav| .{ | 5075 | .nav => |nav| .{ |
| 4887 | (try elf.navMapIndex(zcu, nav)).symbol(elf), | 5076 | (try elf.navMapIndex(zcu, nav)).symbol(elf), |
| 4888 | navType(ip, ip.getNav(nav).resolved.?, elf.base.comp.config.any_non_single_threaded), | 5077 | elf.navType(ip.getNav(nav).resolved.?), |
| 4889 | }, | 5078 | }, |
| 4890 | .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, | 5079 | .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, |
| 4891 | }; | 5080 | }; |
| ... | @@ -4987,13 +5176,13 @@ pub fn printNode( | ... | @@ -4987,13 +5176,13 @@ pub fn printNode( |
| 4987 | try w.writeByte(')'); | 5176 | try w.writeByte(')'); |
| 4988 | }, | 5177 | }, |
| 4989 | }, | 5178 | }, |
| 4990 | .section => |shndx| try w.print("({s})", .{shndx.name(elf)}), | 5179 | .section => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}), |
| 4991 | .input_section => |isi| { | 5180 | .input_section => |isi| { |
| 4992 | const ii = isi.input(elf); | 5181 | const ii = isi.input(elf); |
| 4993 | try w.print("({f}{f}, {s})", .{ | 5182 | try w.print("({f}{f}, {s})", .{ |
| 4994 | ii.path(elf).fmtEscapeString(), | 5183 | ii.path(elf).fmtEscapeString(), |
| 4995 | fmtMemberString(ii.member(elf)), | 5184 | fmtMemberString(ii.member(elf)), |
| 4996 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf), | 5185 | elf.getNode(isi.node(elf).parent(&elf.mf)).section.name(elf).slice(elf), |
| 4997 | }); | 5186 | }); |
| 4998 | }, | 5187 | }, |
| 4999 | .nav => |nmi| { | 5188 | .nav => |nmi| { |