| ... | ... | @@ -1241,44 +1241,68 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1241 | 1241 | // Scan and create missing synthetic entries such as GOT indirection. |
| 1242 | 1242 | try self.scanRelocs(); |
| 1243 | 1243 | |
| 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 | 1254 | // Allocate atoms parsed from input object files, followed by allocating |
| 1245 | 1255 | // linker-defined synthetic symbols. |
| 1246 | 1256 | try self.allocateObjects(); |
| 1247 | 1257 | self.allocateLinkerDefinedSymbols(); |
| 1258 | try self.updateSyntheticSectionSizes(); |
| 1248 | 1259 | |
| 1249 | | // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't |
| 1250 | | // get mapped by the loader |
| 1251 | | if (self.data_section_index) |data_shndx| blk: { |
| 1252 | | const bss_shndx = self.bss_section_index orelse break :blk; |
| 1253 | | const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?; |
| 1254 | | const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?; |
| 1255 | | self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset; |
| 1256 | | self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset; |
| 1257 | | } |
| 1258 | | |
| 1259 | | // Same treatment for .tbss section. |
| 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; |
| 1260 | // Look for entry address in objects if not set by the incremental compiler. |
| 1261 | if (self.entry_addr == null) { |
| 1262 | const entry: ?[]const u8 = entry: { |
| 1263 | if (self.base.options.entry) |entry| break :entry entry; |
| 1264 | if (!self.isDynLib()) break :entry "_start"; |
| 1265 | break :entry null; |
| 1266 | }; |
| 1267 | self.entry_addr = if (entry) |name| entry_addr: { |
| 1268 | const global_index = self.globalByName(name) orelse break :entry_addr null; |
| 1269 | break :entry_addr self.symbol(global_index).value; |
| 1270 | } else null; |
| 1277 | 1271 | } |
| 1278 | 1272 | |
| 1279 | 1273 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 1280 | 1274 | // the relocations, and commit objects to file. |
| 1281 | 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 | 1306 | const zig_module = self.file(index).?.zig_module; |
| 1283 | 1307 | for (zig_module.atoms.items) |atom_index| { |
| 1284 | 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 | 1315 | try atom_ptr.resolveRelocs(self, code); |
| 1292 | 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 | | } |
| 1309 | 1318 | |
| 1310 | | if (self.dwarf) |*dw| { |
| 1311 | | if (self.debug_abbrev_section_dirty) { |
| 1312 | | try dw.writeDbgAbbrev(); |
| 1313 | | if (!self.shdr_table_dirty) { |
| 1314 | | // Then it won't get written with the others and we need to do it. |
| 1315 | | try self.writeShdr(self.debug_abbrev_section_index.?); |
| 1319 | if (self.dwarf) |*dw| { |
| 1320 | if (self.debug_abbrev_section_dirty) { |
| 1321 | try dw.writeDbgAbbrev(); |
| 1322 | if (!self.shdr_table_dirty) { |
| 1323 | // Then it won't get written with the others and we need to do it. |
| 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 | | } |
| 1319 | 1328 | |
| 1320 | | if (self.debug_info_header_dirty) { |
| 1321 | | // 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. |
| 1323 | | const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 1324 | | const low_pc = text_phdr.p_vaddr; |
| 1325 | | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; |
| 1326 | | try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc); |
| 1327 | | self.debug_info_header_dirty = false; |
| 1328 | | } |
| 1329 | if (self.debug_info_header_dirty) { |
| 1330 | // Currently only one compilation unit is supported, so the address range is simply |
| 1331 | // identical to the main program header virtual address and memory size. |
| 1332 | const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 1333 | const low_pc = text_phdr.p_vaddr; |
| 1334 | const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; |
| 1335 | try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc); |
| 1336 | self.debug_info_header_dirty = false; |
| 1337 | } |
| 1329 | 1338 | |
| 1330 | | if (self.debug_aranges_section_dirty) { |
| 1331 | | // 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. |
| 1333 | | const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 1334 | | try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); |
| 1335 | | if (!self.shdr_table_dirty) { |
| 1336 | | // Then it won't get written with the others and we need to do it. |
| 1337 | | try self.writeShdr(self.debug_aranges_section_index.?); |
| 1339 | if (self.debug_aranges_section_dirty) { |
| 1340 | // Currently only one compilation unit is supported, so the address range is simply |
| 1341 | // identical to the main program header virtual address and memory size. |
| 1342 | const text_phdr = &self.phdrs.items[self.phdr_load_re_index.?]; |
| 1343 | try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz); |
| 1344 | if (!self.shdr_table_dirty) { |
| 1345 | // Then it won't get written with the others and we need to do it. |
| 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 | | } |
| 1341 | 1350 | |
| 1342 | | if (self.debug_line_header_dirty) { |
| 1343 | | try dw.writeDbgLineHeader(); |
| 1344 | | self.debug_line_header_dirty = false; |
| 1345 | | } |
| 1351 | if (self.debug_line_header_dirty) { |
| 1352 | try dw.writeDbgLineHeader(); |
| 1353 | self.debug_line_header_dirty = false; |
| 1354 | } |
| 1346 | 1355 | |
| 1347 | | if (self.debug_str_section_index) |index| { |
| 1348 | | if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[index].sh_size) { |
| 1349 | | try self.growNonAllocSection(index, dw.strtab.buffer.items.len, 1, false); |
| 1350 | | const shdr = self.shdrs.items[index]; |
| 1351 | | try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset); |
| 1352 | | self.debug_strtab_dirty = false; |
| 1356 | if (self.debug_str_section_index) |shndx| { |
| 1357 | if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) { |
| 1358 | try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false); |
| 1359 | const shdr = self.shdrs.items[shndx]; |
| 1360 | try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset); |
| 1361 | self.debug_strtab_dirty = false; |
| 1362 | } |
| 1353 | 1363 | } |
| 1354 | 1364 | } |
| 1355 | 1365 | } |
| 1356 | 1366 | |
| 1357 | | // Generate and emit non-incremental sections. |
| 1358 | | try self.initSyntheticSections(); |
| 1359 | | try self.updateSyntheticSectionSizes(); |
| 1360 | | try self.writeSyntheticSections(); |
| 1361 | | |
| 1362 | 1367 | if (self.phdr_table_dirty) { |
| 1363 | 1368 | const phsize: u64 = switch (self.ptr_width) { |
| 1364 | 1369 | .p32 => @sizeOf(elf.Elf32_Phdr), |
| ... | ... | @@ -1470,6 +1475,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1470 | 1475 | } |
| 1471 | 1476 | self.shdr_table_dirty = false; |
| 1472 | 1477 | } |
| 1478 | |
| 1479 | try self.writeSyntheticSections(); |
| 1480 | try self.writeObjects(); |
| 1481 | |
| 1473 | 1482 | if (self.entry_addr == null and self.base.options.effectiveOutputMode() == .Exe) { |
| 1474 | 1483 | log.debug("flushing. no_entry_point_found = true", .{}); |
| 1475 | 1484 | self.error_flags.no_entry_point_found = true; |
| ... | ... | @@ -3420,6 +3429,18 @@ fn allocateLinkerDefinedSymbols(self: *Elf) void { |
| 3420 | 3429 | } |
| 3421 | 3430 | } |
| 3422 | 3431 | |
| 3432 | fn 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 | |
| 3423 | 3444 | fn initSyntheticSections(self: *Elf) !void { |
| 3424 | 3445 | const small_ptr = switch (self.ptr_width) { |
| 3425 | 3446 | .p32 => true, |