Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 103 additions & 1 deletion src/link/Elf/ZigObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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(.{
Expand Down
39 changes: 39 additions & 0 deletions test/link/elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 }));

Expand Down Expand Up @@ -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);
Expand Down