diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 20e5b3d2e3..c9ba0cb1b3 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -1140,7 +1140,109 @@ fn getNavShdrIndex( const ptr_size = elf_file.ptrWidthBytes(); const ip = &zcu.intern_pool; const nav_val = zcu.navValue(nav_index); - if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) { + const is_func = ip.isFunctionType(nav_val.typeOf(zcu).toIntern()); + if (ip.getNav(nav_index).getLinkSection().unwrap()) |@"linksection"| { + const section_name = @"linksection".toSlice(ip); + if (elf_file.sectionByName(section_name)) |osec| { + if (is_func) { + elf_file.sections.items(.shdr)[osec].sh_flags |= elf.SHF_EXECINSTR; + } else { + elf_file.sections.items(.shdr)[osec].sh_flags |= elf.SHF_WRITE; + } + return osec; + } + const osec = try elf_file.addSection(.{ + .type = elf.SHT_PROGBITS, + .flags = elf.SHF_ALLOC | @as(u64, if (is_func) elf.SHF_EXECINSTR else elf.SHF_WRITE), + .name = try elf_file.insertShString(section_name), + .addralign = 1, + }); + const section_index = try self.addSectionSymbol(gpa, try self.addString(gpa, section_name), osec); + if (std.mem.eql(u8, section_name, ".text")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR; + self.text_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".text.")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR; + } else if (std.mem.eql(u8, section_name, ".rodata")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC; + self.rodata_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".rodata.")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC; + } else if (std.mem.eql(u8, section_name, ".data.rel.ro")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + self.data_relro_index = section_index; + } else if (std.mem.eql(u8, section_name, ".data")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + self.data_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".data.")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + } else if (std.mem.eql(u8, section_name, ".bss")) { + const shdr = &elf_file.sections.items(.shdr)[osec]; + shdr.sh_type = elf.SHT_NOBITS; + shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + self.bss_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".bss.")) { + const shdr = &elf_file.sections.items(.shdr)[osec]; + shdr.sh_type = elf.SHT_NOBITS; + shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + } else if (std.mem.eql(u8, section_name, ".tdata")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS; + self.tdata_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".tdata.")) { + elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS; + } else if (std.mem.eql(u8, section_name, ".tbss")) { + const shdr = &elf_file.sections.items(.shdr)[osec]; + shdr.sh_type = elf.SHT_NOBITS; + shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS; + self.tbss_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".tbss.")) { + const shdr = &elf_file.sections.items(.shdr)[osec]; + shdr.sh_type = elf.SHT_NOBITS; + shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS; + } else if (std.mem.eql(u8, section_name, ".eh_frame")) { + const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result; + const shdr = &elf_file.sections.items(.shdr)[osec]; + if (target.cpu.arch == .x86_64) shdr.sh_type = elf.SHT_X86_64_UNWIND; + shdr.sh_flags = elf.SHF_ALLOC; + self.eh_frame_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_info")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_info_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_abbrev")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_abbrev_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_aranges")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_aranges_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_str")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_str_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_line")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_line_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_line_str")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_line_str_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_loclists")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_loclists_index = section_index; + } else if (std.mem.eql(u8, section_name, ".debug_rnglists")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + self.debug_rnglists_index = section_index; + } else if (std.mem.startsWith(u8, section_name, ".debug")) { + elf_file.sections.items(.shdr)[osec].sh_flags = 0; + } else if (std.mem.eql(u8, section_name, ".init_array") or std.mem.startsWith(u8, section_name, ".init_array.")) { + const shdr = &elf_file.sections.items(.shdr)[osec]; + shdr.sh_type = elf.SHT_INIT_ARRAY; + shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + } else if (std.mem.eql(u8, section_name, ".fini_array") or std.mem.startsWith(u8, section_name, ".fini_array.")) { + const shdr = &elf_file.sections.items(.shdr)[osec]; + shdr.sh_type = elf.SHT_FINI_ARRAY; + shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE; + } + return osec; + } + if (is_func) { if (self.text_index) |symbol_index| return self.symbol(symbol_index).outputShndx(elf_file).?; const osec = try elf_file.addSection(.{ diff --git a/test/link/elf.zig b/test/link/elf.zig index 1d6de32f0d..16ee824da7 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -73,6 +73,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { elf_step.dependOn(testLinkingC(b, .{ .target = musl_target })); elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target })); elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target })); + elf_step.dependOn(testLinksection(b, .{ .target = musl_target })); elf_step.dependOn(testMergeStrings(b, .{ .target = musl_target })); elf_step.dependOn(testMergeStrings2(b, .{ .target = musl_target })); // https://github.com/ziglang/zig/issues/17451 @@ -165,6 +166,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step { elf_step.dependOn(testLinkingObj(b, .{ .use_llvm = false, .target = default_target })); elf_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = default_target })); elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false, .target = default_target })); + elf_step.dependOn(testLinksection(b, .{ .use_llvm = false, .target = default_target })); elf_step.dependOn(testImportingDataDynamic(b, .{ .use_llvm = false, .target = x86_64_gnu })); elf_step.dependOn(testImportingDataStatic(b, .{ .use_llvm = false, .target = x86_64_musl })); @@ -2439,6 +2441,43 @@ fn testLinkingZig(b: *Build, opts: Options) *Step { return test_step; } +fn testLinksection(b: *Build, opts: Options) *Step { + const test_step = addTestStep(b, "linksection", opts); + + const obj = addObject(b, opts, .{ .name = "main", .zig_source_bytes = + \\export var test_global: u32 linksection(".TestGlobal") = undefined; + \\export fn testFn() linksection(".TestFn") callconv(.c) void { + \\ TestGenericFn("A").f(); + \\} + \\fn TestGenericFn(comptime suffix: []const u8) type { + \\ return struct { + \\ fn f() linksection(".TestGenFn" ++ suffix) void {} + \\ }; + \\} + }); + + const check = obj.checkObject(); + check.checkInSymtab(); + check.checkContains("SECTION LOCAL DEFAULT .TestGlobal"); + check.checkInSymtab(); + check.checkContains("SECTION LOCAL DEFAULT .TestFn"); + check.checkInSymtab(); + check.checkContains("SECTION LOCAL DEFAULT .TestGenFnA"); + check.checkInSymtab(); + check.checkContains("OBJECT GLOBAL DEFAULT test_global"); + check.checkInSymtab(); + check.checkContains("FUNC GLOBAL DEFAULT testFn"); + + if (opts.optimize == .Debug) { + check.checkInSymtab(); + check.checkContains("FUNC LOCAL DEFAULT main.TestGenericFn("); + } + + test_step.dependOn(&check.step); + + return test_step; +} + // Adapted from https://github.com/rui314/mold/blob/main/test/elf/mergeable-strings.sh fn testMergeStrings(b: *Build, opts: Options) *Step { const test_step = addTestStep(b, "merge-strings", opts);