Skip to content

Commit 09bc118

Browse files
jacobly0andrewrk
authored andcommitted
Elf: implement linksection
Closes #24330
1 parent 8e9f2f0 commit 09bc118

File tree

2 files changed

+142
-1
lines changed

2 files changed

+142
-1
lines changed

src/link/Elf/ZigObject.zig

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,109 @@ fn getNavShdrIndex(
11401140
const ptr_size = elf_file.ptrWidthBytes();
11411141
const ip = &zcu.intern_pool;
11421142
const nav_val = zcu.navValue(nav_index);
1143-
if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) {
1143+
const is_func = ip.isFunctionType(nav_val.typeOf(zcu).toIntern());
1144+
if (ip.getNav(nav_index).getLinkSection().unwrap()) |@"linksection"| {
1145+
const section_name = @"linksection".toSlice(ip);
1146+
if (elf_file.sectionByName(section_name)) |osec| {
1147+
if (is_func) {
1148+
elf_file.sections.items(.shdr)[osec].sh_flags |= elf.SHF_EXECINSTR;
1149+
} else {
1150+
elf_file.sections.items(.shdr)[osec].sh_flags |= elf.SHF_WRITE;
1151+
}
1152+
return osec;
1153+
}
1154+
const osec = try elf_file.addSection(.{
1155+
.type = elf.SHT_PROGBITS,
1156+
.flags = elf.SHF_ALLOC | @as(u64, if (is_func) elf.SHF_EXECINSTR else elf.SHF_WRITE),
1157+
.name = try elf_file.insertShString(section_name),
1158+
.addralign = 1,
1159+
});
1160+
const section_index = try self.addSectionSymbol(gpa, try self.addString(gpa, section_name), osec);
1161+
if (std.mem.eql(u8, section_name, ".text")) {
1162+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR;
1163+
self.text_index = section_index;
1164+
} else if (std.mem.startsWith(u8, section_name, ".text.")) {
1165+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR;
1166+
} else if (std.mem.eql(u8, section_name, ".rodata")) {
1167+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC;
1168+
self.rodata_index = section_index;
1169+
} else if (std.mem.startsWith(u8, section_name, ".rodata.")) {
1170+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC;
1171+
} else if (std.mem.eql(u8, section_name, ".data.rel.ro")) {
1172+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1173+
self.data_relro_index = section_index;
1174+
} else if (std.mem.eql(u8, section_name, ".data")) {
1175+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1176+
self.data_index = section_index;
1177+
} else if (std.mem.startsWith(u8, section_name, ".data.")) {
1178+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1179+
} else if (std.mem.eql(u8, section_name, ".bss")) {
1180+
const shdr = &elf_file.sections.items(.shdr)[osec];
1181+
shdr.sh_type = elf.SHT_NOBITS;
1182+
shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1183+
self.bss_index = section_index;
1184+
} else if (std.mem.startsWith(u8, section_name, ".bss.")) {
1185+
const shdr = &elf_file.sections.items(.shdr)[osec];
1186+
shdr.sh_type = elf.SHT_NOBITS;
1187+
shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1188+
} else if (std.mem.eql(u8, section_name, ".tdata")) {
1189+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS;
1190+
self.tdata_index = section_index;
1191+
} else if (std.mem.startsWith(u8, section_name, ".tdata.")) {
1192+
elf_file.sections.items(.shdr)[osec].sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS;
1193+
} else if (std.mem.eql(u8, section_name, ".tbss")) {
1194+
const shdr = &elf_file.sections.items(.shdr)[osec];
1195+
shdr.sh_type = elf.SHT_NOBITS;
1196+
shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS;
1197+
self.tbss_index = section_index;
1198+
} else if (std.mem.startsWith(u8, section_name, ".tbss.")) {
1199+
const shdr = &elf_file.sections.items(.shdr)[osec];
1200+
shdr.sh_type = elf.SHT_NOBITS;
1201+
shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS;
1202+
} else if (std.mem.eql(u8, section_name, ".eh_frame")) {
1203+
const target = &zcu.navFileScope(nav_index).mod.?.resolved_target.result;
1204+
const shdr = &elf_file.sections.items(.shdr)[osec];
1205+
if (target.cpu.arch == .x86_64) shdr.sh_type = elf.SHT_X86_64_UNWIND;
1206+
shdr.sh_flags = elf.SHF_ALLOC;
1207+
self.eh_frame_index = section_index;
1208+
} else if (std.mem.eql(u8, section_name, ".debug_info")) {
1209+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1210+
self.debug_info_index = section_index;
1211+
} else if (std.mem.eql(u8, section_name, ".debug_abbrev")) {
1212+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1213+
self.debug_abbrev_index = section_index;
1214+
} else if (std.mem.eql(u8, section_name, ".debug_aranges")) {
1215+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1216+
self.debug_aranges_index = section_index;
1217+
} else if (std.mem.eql(u8, section_name, ".debug_str")) {
1218+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1219+
self.debug_str_index = section_index;
1220+
} else if (std.mem.eql(u8, section_name, ".debug_line")) {
1221+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1222+
self.debug_line_index = section_index;
1223+
} else if (std.mem.eql(u8, section_name, ".debug_line_str")) {
1224+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1225+
self.debug_line_str_index = section_index;
1226+
} else if (std.mem.eql(u8, section_name, ".debug_loclists")) {
1227+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1228+
self.debug_loclists_index = section_index;
1229+
} else if (std.mem.eql(u8, section_name, ".debug_rnglists")) {
1230+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1231+
self.debug_rnglists_index = section_index;
1232+
} else if (std.mem.startsWith(u8, section_name, ".debug")) {
1233+
elf_file.sections.items(.shdr)[osec].sh_flags = 0;
1234+
} else if (std.mem.eql(u8, section_name, ".init_array") or std.mem.startsWith(u8, section_name, ".init_array.")) {
1235+
const shdr = &elf_file.sections.items(.shdr)[osec];
1236+
shdr.sh_type = elf.SHT_INIT_ARRAY;
1237+
shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1238+
} else if (std.mem.eql(u8, section_name, ".fini_array") or std.mem.startsWith(u8, section_name, ".fini_array.")) {
1239+
const shdr = &elf_file.sections.items(.shdr)[osec];
1240+
shdr.sh_type = elf.SHT_FINI_ARRAY;
1241+
shdr.sh_flags = elf.SHF_ALLOC | elf.SHF_WRITE;
1242+
}
1243+
return osec;
1244+
}
1245+
if (is_func) {
11441246
if (self.text_index) |symbol_index|
11451247
return self.symbol(symbol_index).outputShndx(elf_file).?;
11461248
const osec = try elf_file.addSection(.{

test/link/elf.zig

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
7373
elf_step.dependOn(testLinkingC(b, .{ .target = musl_target }));
7474
elf_step.dependOn(testLinkingCpp(b, .{ .target = musl_target }));
7575
elf_step.dependOn(testLinkingZig(b, .{ .target = musl_target }));
76+
elf_step.dependOn(testLinksection(b, .{ .target = musl_target }));
7677
elf_step.dependOn(testMergeStrings(b, .{ .target = musl_target }));
7778
elf_step.dependOn(testMergeStrings2(b, .{ .target = musl_target }));
7879
// https://github.com/ziglang/zig/issues/17451
@@ -165,6 +166,7 @@ pub fn testAll(b: *Build, build_opts: BuildOptions) *Step {
165166
elf_step.dependOn(testLinkingObj(b, .{ .use_llvm = false, .target = default_target }));
166167
elf_step.dependOn(testLinkingStaticLib(b, .{ .use_llvm = false, .target = default_target }));
167168
elf_step.dependOn(testLinkingZig(b, .{ .use_llvm = false, .target = default_target }));
169+
elf_step.dependOn(testLinksection(b, .{ .use_llvm = false, .target = default_target }));
168170
elf_step.dependOn(testImportingDataDynamic(b, .{ .use_llvm = false, .target = x86_64_gnu }));
169171
elf_step.dependOn(testImportingDataStatic(b, .{ .use_llvm = false, .target = x86_64_musl }));
170172

@@ -2439,6 +2441,43 @@ fn testLinkingZig(b: *Build, opts: Options) *Step {
24392441
return test_step;
24402442
}
24412443

2444+
fn testLinksection(b: *Build, opts: Options) *Step {
2445+
const test_step = addTestStep(b, "linksection", opts);
2446+
2447+
const obj = addObject(b, opts, .{ .name = "main", .zig_source_bytes =
2448+
\\export var test_global: u32 linksection(".TestGlobal") = undefined;
2449+
\\export fn testFn() linksection(".TestFn") callconv(.c) void {
2450+
\\ TestGenericFn("A").f();
2451+
\\}
2452+
\\fn TestGenericFn(comptime suffix: []const u8) type {
2453+
\\ return struct {
2454+
\\ fn f() linksection(".TestGenFn" ++ suffix) void {}
2455+
\\ };
2456+
\\}
2457+
});
2458+
2459+
const check = obj.checkObject();
2460+
check.checkInSymtab();
2461+
check.checkContains("SECTION LOCAL DEFAULT .TestGlobal");
2462+
check.checkInSymtab();
2463+
check.checkContains("SECTION LOCAL DEFAULT .TestFn");
2464+
check.checkInSymtab();
2465+
check.checkContains("SECTION LOCAL DEFAULT .TestGenFnA");
2466+
check.checkInSymtab();
2467+
check.checkContains("OBJECT GLOBAL DEFAULT test_global");
2468+
check.checkInSymtab();
2469+
check.checkContains("FUNC GLOBAL DEFAULT testFn");
2470+
2471+
if (opts.optimize == .Debug) {
2472+
check.checkInSymtab();
2473+
check.checkContains("FUNC LOCAL DEFAULT main.TestGenericFn(");
2474+
}
2475+
2476+
test_step.dependOn(&check.step);
2477+
2478+
return test_step;
2479+
}
2480+
24422481
// Adapted from https://github.com/rui314/mold/blob/main/test/elf/mergeable-strings.sh
24432482
fn testMergeStrings(b: *Build, opts: Options) *Step {
24442483
const test_step = addTestStep(b, "merge-strings", opts);

0 commit comments

Comments
 (0)