authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-02 18:24:05+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-16 19:33:04+02:00
log679accd8873ab08ebb0e8d7b2b537c18bd77d821
tree2bd0e9bf6aa95d82e7ce01ec81b0f346ae9f8399
parent509da2316c2f8ec3a3939df09ca288f92dc55905

elf: initialize output sections from input objects in a separate step


2 files changed, 113 insertions(+), 113 deletions(-)

src/link/Elf.zig+106-85
...@@ -1241,44 +1241,68 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1241,44 +1241,68 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1241 // Scan and create missing synthetic entries such as GOT indirection.1241 // Scan and create missing synthetic entries such as GOT indirection.
1242 try self.scanRelocs();1242 try self.scanRelocs();
12431243
1244 // Generate and emit non-incremental sections.
1245 try self.initSections();
1246 try self.initSyntheticSections();
1247
1248 // Dump the state for easy debugging.
1249 // State can be dumped via `--debug-log link_state`.
1250 if (build_options.enable_logging) {
1251 state_log.debug("{}", .{self.dumpState()});
1252 }
1253
1244 // Allocate atoms parsed from input object files, followed by allocating1254 // Allocate atoms parsed from input object files, followed by allocating
1245 // linker-defined synthetic symbols.1255 // linker-defined synthetic symbols.
1246 try self.allocateObjects();1256 try self.allocateObjects();
1247 self.allocateLinkerDefinedSymbols();1257 self.allocateLinkerDefinedSymbols();
1258 try self.updateSyntheticSectionSizes();
12481259
1249 // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't1260 // Look for entry address in objects if not set by the incremental compiler.
1250 // get mapped by the loader1261 if (self.entry_addr == null) {
1251 if (self.data_section_index) |data_shndx| blk: {1262 const entry: ?[]const u8 = entry: {
1252 const bss_shndx = self.bss_section_index orelse break :blk;1263 if (self.base.options.entry) |entry| break :entry entry;
1253 const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?;1264 if (!self.isDynLib()) break :entry "_start";
1254 const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?;1265 break :entry null;
1255 self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset;1266 };
1256 self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset;1267 self.entry_addr = if (entry) |name| entry_addr: {
1257 }1268 const global_index = self.globalByName(name) orelse break :entry_addr null;
12581269 break :entry_addr self.symbol(global_index).value;
1259 // Same treatment for .tbss section.1270 } else null;
1260 if (self.tdata_section_index) |tdata_shndx| blk: {
1261 const tbss_shndx = self.tbss_section_index orelse break :blk;
1262 const tdata_phndx = self.phdr_to_shdr_table.get(tdata_shndx).?;
1263 const tbss_phndx = self.phdr_to_shdr_table.get(tbss_shndx).?;
1264 self.shdrs.items[tbss_shndx].sh_offset = self.shdrs.items[tdata_shndx].sh_offset;
1265 self.phdrs.items[tbss_phndx].p_offset = self.phdrs.items[tdata_phndx].p_offset;
1266 }
1267
1268 if (self.phdr_tls_index) |tls_index| {
1269 const tdata_phdr = &self.phdrs.items[self.phdr_load_tls_data_index.?];
1270 const tbss_phdr = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?];
1271 const phdr = &self.phdrs.items[tls_index];
1272 phdr.p_offset = tdata_phdr.p_offset;
1273 phdr.p_filesz = tdata_phdr.p_filesz;
1274 phdr.p_vaddr = tdata_phdr.p_vaddr;
1275 phdr.p_paddr = tdata_phdr.p_vaddr;
1276 phdr.p_memsz = tbss_phdr.p_vaddr + tbss_phdr.p_memsz - tdata_phdr.p_vaddr;
1277 }1271 }
12781272
1279 // Beyond this point, everything has been allocated a virtual address and we can resolve1273 // Beyond this point, everything has been allocated a virtual address and we can resolve
1280 // the relocations, and commit objects to file.1274 // the relocations, and commit objects to file.
1281 if (self.zig_module_index) |index| {1275 if (self.zig_module_index) |index| {
1276 // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't
1277 // get mapped by the loader
1278 if (self.data_section_index) |data_shndx| blk: {
1279 const bss_shndx = self.bss_section_index orelse break :blk;
1280 const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?;
1281 const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?;
1282 self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset;
1283 self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset;
1284 }
1285
1286 // Same treatment for .tbss section.
1287 if (self.tdata_section_index) |tdata_shndx| blk: {
1288 const tbss_shndx = self.tbss_section_index orelse break :blk;
1289 const tdata_phndx = self.phdr_to_shdr_table.get(tdata_shndx).?;
1290 const tbss_phndx = self.phdr_to_shdr_table.get(tbss_shndx).?;
1291 self.shdrs.items[tbss_shndx].sh_offset = self.shdrs.items[tdata_shndx].sh_offset;
1292 self.phdrs.items[tbss_phndx].p_offset = self.phdrs.items[tdata_phndx].p_offset;
1293 }
1294
1295 if (self.phdr_tls_index) |tls_index| {
1296 const tdata_phdr = &self.phdrs.items[self.phdr_load_tls_data_index.?];
1297 const tbss_phdr = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?];
1298 const phdr = &self.phdrs.items[tls_index];
1299 phdr.p_offset = tdata_phdr.p_offset;
1300 phdr.p_filesz = tdata_phdr.p_filesz;
1301 phdr.p_vaddr = tdata_phdr.p_vaddr;
1302 phdr.p_paddr = tdata_phdr.p_vaddr;
1303 phdr.p_memsz = tbss_phdr.p_vaddr + tbss_phdr.p_memsz - tdata_phdr.p_vaddr;
1304 }
1305
1282 const zig_module = self.file(index).?.zig_module;1306 const zig_module = self.file(index).?.zig_module;
1283 for (zig_module.atoms.items) |atom_index| {1307 for (zig_module.atoms.items) |atom_index| {
1284 const atom_ptr = self.atom(atom_index) orelse continue;1308 const atom_ptr = self.atom(atom_index) orelse continue;
...@@ -1291,74 +1315,55 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1291,74 +1315,55 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1291 try atom_ptr.resolveRelocs(self, code);1315 try atom_ptr.resolveRelocs(self, code);
1292 try self.base.file.?.pwriteAll(code, file_offset);1316 try self.base.file.?.pwriteAll(code, file_offset);
1293 }1317 }
1294 }
1295 try self.writeObjects();
1296
1297 // Look for entry address in objects if not set by the incremental compiler.
1298 if (self.entry_addr == null) {
1299 const entry: ?[]const u8 = entry: {
1300 if (self.base.options.entry) |entry| break :entry entry;
1301 if (!self.isDynLib()) break :entry "_start";
1302 break :entry null;
1303 };
1304 self.entry_addr = if (entry) |name| entry_addr: {
1305 const global_index = self.globalByName(name) orelse break :entry_addr null;
1306 break :entry_addr self.symbol(global_index).value;
1307 } else null;
1308 }
13091318
1310 if (self.dwarf) |*dw| {1319 if (self.dwarf) |*dw| {
1311 if (self.debug_abbrev_section_dirty) {1320 if (self.debug_abbrev_section_dirty) {
1312 try dw.writeDbgAbbrev();1321 try dw.writeDbgAbbrev();
1313 if (!self.shdr_table_dirty) {1322 if (!self.shdr_table_dirty) {
1314 // Then it won't get written with the others and we need to do it.1323 // Then it won't get written with the others and we need to do it.
1315 try self.writeShdr(self.debug_abbrev_section_index.?);1324 try self.writeShdr(self.debug_abbrev_section_index.?);
1325 }
1326 self.debug_abbrev_section_dirty = false;
1316 }1327 }
1317 self.debug_abbrev_section_dirty = false;
1318 }
13191328
1320 if (self.debug_info_header_dirty) {1329 if (self.debug_info_header_dirty) {
1321 // Currently only one compilation unit is supported, so the address range is simply1330 // Currently only one compilation unit is supported, so the address range is simply
1322 // identical to the main program header virtual address and memory size.1331 // identical to the main program header virtual address and memory size.
1323 const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?];1332 const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?];
1324 const low_pc = text_phdr.p_vaddr;1333 const low_pc = text_phdr.p_vaddr;
1325 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1334 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1326 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);1335 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
1327 self.debug_info_header_dirty = false;1336 self.debug_info_header_dirty = false;
1328 }1337 }
13291338
1330 if (self.debug_aranges_section_dirty) {1339 if (self.debug_aranges_section_dirty) {
1331 // Currently only one compilation unit is supported, so the address range is simply1340 // Currently only one compilation unit is supported, so the address range is simply
1332 // identical to the main program header virtual address and memory size.1341 // identical to the main program header virtual address and memory size.
1333 const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?];1342 const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?];
1334 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);1343 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1335 if (!self.shdr_table_dirty) {1344 if (!self.shdr_table_dirty) {
1336 // Then it won't get written with the others and we need to do it.1345 // Then it won't get written with the others and we need to do it.
1337 try self.writeShdr(self.debug_aranges_section_index.?);1346 try self.writeShdr(self.debug_aranges_section_index.?);
1347 }
1348 self.debug_aranges_section_dirty = false;
1338 }1349 }
1339 self.debug_aranges_section_dirty = false;
1340 }
13411350
1342 if (self.debug_line_header_dirty) {1351 if (self.debug_line_header_dirty) {
1343 try dw.writeDbgLineHeader();1352 try dw.writeDbgLineHeader();
1344 self.debug_line_header_dirty = false;1353 self.debug_line_header_dirty = false;
1345 }1354 }
13461355
1347 if (self.debug_str_section_index) |index| {1356 if (self.debug_str_section_index) |shndx| {
1348 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[index].sh_size) {1357 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) {
1349 try self.growNonAllocSection(index, dw.strtab.buffer.items.len, 1, false);1358 try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
1350 const shdr = self.shdrs.items[index];1359 const shdr = self.shdrs.items[shndx];
1351 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);1360 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
1352 self.debug_strtab_dirty = false;1361 self.debug_strtab_dirty = false;
1362 }
1353 }1363 }
1354 }1364 }
1355 }1365 }
13561366
1357 // Generate and emit non-incremental sections.
1358 try self.initSyntheticSections();
1359 try self.updateSyntheticSectionSizes();
1360 try self.writeSyntheticSections();
1361
1362 if (self.phdr_table_dirty) {1367 if (self.phdr_table_dirty) {
1363 const phsize: u64 = switch (self.ptr_width) {1368 const phsize: u64 = switch (self.ptr_width) {
1364 .p32 => @sizeOf(elf.Elf32_Phdr),1369 .p32 => @sizeOf(elf.Elf32_Phdr),
...@@ -1470,6 +1475,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1470,6 +1475,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1470 }1475 }
1471 self.shdr_table_dirty = false;1476 self.shdr_table_dirty = false;
1472 }1477 }
1478
1479 try self.writeSyntheticSections();
1480 try self.writeObjects();
1481
1473 if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {1482 if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) {
1474 log.debug("flushing. no_entry_point_found = true", .{});1483 log.debug("flushing. no_entry_point_found = true", .{});
1475 self.error_flags.no_entry_point_found = true;1484 self.error_flags.no_entry_point_found = true;
...@@ -3420,6 +3429,18 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {...@@ -3420,6 +3429,18 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void {
3420 }3429 }
3421}3430}
34223431
3432fn initSections(self: *Elf) !void {
3433 for (self.objects.items) |index| {
3434 const object = self.file(index).?.object;
3435 for (object.atoms.items) |atom_index| {
3436 const atom_ptr = self.atom(atom_index) orelse continue;
3437 if (!atom_ptr.flags.alive) continue;
3438 const shdr = atom_ptr.inputShdr(self);
3439 atom_ptr.output_section_index = try object.getOutputSectionIndex(self, shdr);
3440 }
3441 }
3442}
3443
3423fn initSyntheticSections(self: *Elf) !void {3444fn initSyntheticSections(self: *Elf) !void {
3424 const small_ptr = switch (self.ptr_width) {3445 const small_ptr = switch (self.ptr_width) {
3425 .p32 => true,3446 .p32 => true,
src/link/Elf/Object.zig+7-28
...@@ -194,10 +194,10 @@ fn addAtom(...@@ -194,10 +194,10 @@ fn addAtom(
194 }194 }
195}195}
196196
197fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {197pub fn getOutputSectionIndex(self: Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) error{OutOfMemory}!u16 {
198 const name = blk: {198 const name = blk: {
199 const name = self.strings.getAssumeExists(shdr.sh_name);199 const name = self.strings.getAssumeExists(shdr.sh_name);
200 // if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;200 if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
201 const sh_name_prefixes: []const [:0]const u8 = &.{201 const sh_name_prefixes: []const [:0]const u8 = &.{
202 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",202 ".text", ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro", ".bss",
203 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",203 ".init_array", ".fini_array", ".tbss", ".tdata", ".gcc_except_table", ".ctors",
...@@ -231,32 +231,11 @@ fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) er...@@ -231,32 +231,11 @@ fn getOutputSectionIndex(self: *Object, elf_file: *Elf, shdr: elf.Elf64_Shdr) er
231 else => flags,231 else => flags,
232 };232 };
233 };233 };
234 const out_shndx = elf_file.sectionByName(name) orelse blk: {234 const out_shndx = elf_file.sectionByName(name) orelse try elf_file.addSection(.{
235 const is_alloc = flags & elf.SHF_ALLOC != 0;235 .type = @"type",
236 const is_write = flags & elf.SHF_WRITE != 0;236 .flags = flags,
237 const is_exec = flags & elf.SHF_EXECINSTR != 0;237 .name = name,
238 if (!is_alloc) {238 });
239 log.err("{}: output section {s} not found", .{ self.fmtPath(), name });
240 @panic("TODO: missing output section!");
241 }
242 var phdr_flags: u32 = elf.PF_R;
243 if (is_write) phdr_flags |= elf.PF_W;
244 if (is_exec) phdr_flags |= elf.PF_X;
245 const phdr_index = try elf_file.allocateSegment(.{
246 .size = Elf.padToIdeal(shdr.sh_size),
247 .alignment = elf_file.page_size,
248 .flags = phdr_flags,
249 });
250 const shndx = try elf_file.allocateAllocSection(.{
251 .name = name,
252 .phdr_index = phdr_index,
253 .alignment = shdr.sh_addralign,
254 .flags = flags,
255 .type = @"type",
256 });
257 try elf_file.last_atom_and_free_list_table.putNoClobber(elf_file.base.allocator, shndx, .{});
258 break :blk shndx;
259 };
260 return out_shndx;239 return out_shndx;
261}240}
262241