authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-28 14:59:09+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-09-28 14:59:09+02:00
log785bd270ed47034aac7a7a231e2aa0ab1254c621
treeeda06ffbeb4a5ba11af47c6030d3363eb2a9cc61
parentaf00ac53b50ca9dc606560f106ef17c488e71249

elf: correctly allocate TLS segment


3 files changed, 70 insertions(+), 23 deletions(-)

src/link/Elf.zig+56-18
......@@ -247,7 +247,8 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
247247 else
248248 elf.VER_NDX_LOCAL;
249249
250 var dwarf: ?Dwarf = if (!options.strip and options.module != null)
250 const use_llvm = options.use_llvm;
251 var dwarf: ?Dwarf = if (!options.strip and options.module != null and !use_llvm)
251252 Dwarf.init(gpa, &self.base, options.target)
252253 else
253254 null;
......@@ -264,7 +265,6 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
264265 .page_size = page_size,
265266 .default_sym_version = default_sym_version,
266267 };
267 const use_llvm = options.use_llvm;
268268 if (use_llvm and options.module != null) {
269269 self.llvm_object = try LlvmObject.create(gpa, options);
270270 }
......@@ -643,6 +643,13 @@ pub fn populateMissingMetadata(self: *Elf) !void {
643643 }
644644
645645 if (self.phdr_load_tls_zerofill_index == null) {
646 // TODO .tbss doesn't need any physical or memory representation (aka a loadable segment)
647 // since the loader only cares about the PT_TLS to work out TLS size. However, when
648 // relocating we need to have .tdata and .tbss contiguously laid out so that we can
649 // work out correct offsets to the start/end of the TLS segment. I am thinking that
650 // perhaps it's possible to completely spoof it by having an abstracted mechanism
651 // for this that wouldn't require us to explicitly track .tbss. Anyhow, for now,
652 // we go the savage route of treating .tbss like .bss.
646653 const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
647654 self.phdr_load_tls_zerofill_index = try self.allocateSegment(.{
648655 .size = 0,
......@@ -655,6 +662,7 @@ pub fn populateMissingMetadata(self: *Elf) !void {
655662 }
656663
657664 if (self.phdr_tls_index == null) {
665 self.phdr_tls_index = @intCast(self.phdrs.items.len);
658666 const phdr_tdata = &self.phdrs.items[self.phdr_load_tls_data_index.?];
659667 const phdr_tbss = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?];
660668 try self.phdrs.append(gpa, .{
......@@ -1280,6 +1288,36 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
12801288 try self.allocateObjects();
12811289 self.allocateLinkerDefinedSymbols();
12821290
1291 // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't
1292 // get mapped by the loader
1293 if (self.data_section_index) |data_shndx| blk: {
1294 const bss_shndx = self.bss_section_index orelse break :blk;
1295 const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?;
1296 const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?;
1297 self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset;
1298 self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset;
1299 }
1300
1301 // Same treatment for .tbss section.
1302 if (self.tdata_section_index) |tdata_shndx| blk: {
1303 const tbss_shndx = self.tbss_section_index orelse break :blk;
1304 const tdata_phndx = self.phdr_to_shdr_table.get(tdata_shndx).?;
1305 const tbss_phndx = self.phdr_to_shdr_table.get(tbss_shndx).?;
1306 self.shdrs.items[tbss_shndx].sh_offset = self.shdrs.items[tdata_shndx].sh_offset;
1307 self.phdrs.items[tbss_phndx].p_offset = self.phdrs.items[tdata_phndx].p_offset;
1308 }
1309
1310 if (self.phdr_tls_index) |tls_index| {
1311 const tdata_phdr = &self.phdrs.items[self.phdr_load_tls_data_index.?];
1312 const tbss_phdr = &self.phdrs.items[self.phdr_load_tls_zerofill_index.?];
1313 const phdr = &self.phdrs.items[tls_index];
1314 phdr.p_offset = tdata_phdr.p_offset;
1315 phdr.p_filesz = tdata_phdr.p_filesz;
1316 phdr.p_vaddr = tdata_phdr.p_vaddr;
1317 phdr.p_paddr = tdata_phdr.p_vaddr;
1318 phdr.p_memsz = tbss_phdr.p_vaddr + tbss_phdr.p_memsz - tdata_phdr.p_vaddr;
1319 }
1320
12831321 // Beyond this point, everything has been allocated a virtual address and we can resolve
12841322 // the relocations, and commit objects to file.
12851323 if (self.zig_module_index) |index| {
......@@ -1325,22 +1363,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
13251363 try self.updateSymtabSize();
13261364 try self.writeSymtab();
13271365
1328 // .bss always overlaps .data in file offset, but is zero-sized in file so it doesn't
1329 // get mapped by the loader
1330 if (self.data_section_index) |data_shndx| blk: {
1331 const bss_shndx = self.bss_section_index orelse break :blk;
1332 const data_phndx = self.phdr_to_shdr_table.get(data_shndx).?;
1333 const bss_phndx = self.phdr_to_shdr_table.get(bss_shndx).?;
1334 self.shdrs.items[bss_shndx].sh_offset = self.shdrs.items[data_shndx].sh_offset;
1335 self.phdrs.items[bss_phndx].p_offset = self.phdrs.items[data_phndx].p_offset;
1336 }
1337
1338 // Same treatment for .tbss section.
1339 if (self.tdata_section_index) |tdata_shndx| blk: {
1340 const tbss_shndx = self.tbss_section_index orelse break :blk;
1341 self.shdrs.items[tbss_shndx].sh_offset = self.shdrs.items[tdata_shndx].sh_offset;
1342 }
1343
13441366 // Dump the state for easy debugging.
13451367 // State can be dumped via `--debug-log link_state`.
13461368 if (build_options.enable_logging) {
......@@ -4066,6 +4088,22 @@ pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupO
40664088 return &self.comdat_groups_owners.items[index];
40674089}
40684090
4091pub fn tpAddress(self: *Elf) u64 {
4092 const index = self.phdr_tls_index orelse return 0;
4093 const phdr = self.phdrs.items[index];
4094 return mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
4095}
4096
4097pub fn dtpAddress(self: *Elf) u64 {
4098 return self.tlsAddress();
4099}
4100
4101pub fn tlsAddress(self: *Elf) u64 {
4102 const index = self.phdr_tls_index orelse return 0;
4103 const phdr = self.phdrs.items[index];
4104 return phdr.p_vaddr;
4105}
4106
40694107const ErrorWithNotes = struct {
40704108 /// Allocated index in misc_errors array.
40714109 index: usize,
src/link/Elf/Atom.zig+11-2
......@@ -388,6 +388,12 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, undefs: anytype) !void {
388388
389389 elf.R_X86_64_PC32 => {},
390390
391 elf.R_X86_64_TPOFF32,
392 elf.R_X86_64_TPOFF64,
393 => {
394 // if (is_shared) self.picError(symbol, rel, elf_file);
395 },
396
391397 else => {
392398 var err = try elf_file.addErrorWithNotes(1);
393399 try err.addMsg(elf_file, "fatal linker error: unhandled relocation type {}", .{
......@@ -473,9 +479,9 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
473479 // Relative offset to the start of the global offset table.
474480 const G = @as(i64, @intCast(target.gotAddress(elf_file))) - GOT;
475481 // // Address of the thread pointer.
476 // const TP = @as(i64, @intCast(elf_file.getTpAddress()));
482 const TP = @as(i64, @intCast(elf_file.tpAddress()));
477483 // // Address of the dynamic thread pointer.
478 // const DTP = @as(i64, @intCast(elf_file.getDtpAddress()));
484 // const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
479485
480486 relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ({s})", .{
481487 fmtRelocType(r_type),
......@@ -522,6 +528,9 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
522528 try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P)));
523529 },
524530
531 elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))),
532 elf.R_X86_64_TPOFF64 => try cwriter.writeIntLittle(i64, S + A - TP),
533
525534 else => {},
526535 }
527536 }
src/link/Elf/Symbol.zig+3-3
......@@ -196,9 +196,9 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
196196 // if (symbol.flags.is_canonical) break :blk symbol.address(.{}, elf_file);
197197 // break :blk 0;
198198 // }
199 // if (st_shndx == elf.SHN_ABS) break :blk symbol.value;
200 // const shdr = &elf_file.sections.items(.shdr)[st_shndx];
201 // if (Elf.shdrIsTls(shdr)) break :blk symbol.value - elf_file.getTlsAddress();
199 if (st_shndx == elf.SHN_ABS) break :blk symbol.value;
200 const shdr = &elf_file.shdrs.items[st_shndx];
201 if (shdr.sh_flags & elf.SHF_TLS != 0) break :blk symbol.value - elf_file.tlsAddress();
202202 break :blk symbol.value;
203203 };
204204 out.* = .{