Skip to content

Commit

Permalink
elf: handle TLS LD model for executables
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Jul 18, 2023
1 parent b7e6513 commit bf984a0
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2507,7 +2507,7 @@ pub inline fn getPltGotEntryAddress(self: *Elf, index: u32) u64 {
}

pub inline fn getTlsLdAddress(self: *Elf) u64 {
return self.getGotEntryAddress(@as(u32, @intCast(self.got.symbols.items.len)));
return self.getGotEntryAddress(self.got.getTlsLdIndex());
}

pub fn getTpAddress(self: *Elf) u64 {
Expand Down
3 changes: 2 additions & 1 deletion src/Elf/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, writer: anytype) !void {

elf.R_X86_64_TLSLD => {
if (elf_file.got.emit_tlsld) {
try cwriter.writeIntLittle(i32, @as(i32, @intCast(@as(i64, @intCast(elf_file.getTlsLdAddress())) + A - P)));
const S_ = @as(i64, @intCast(elf_file.getTlsLdAddress()));
try cwriter.writeIntLittle(i32, @as(i32, @intCast(S_ + A - P)));
} else {
try relaxTlsLdToLe(
relocs[i .. i + 2],
Expand Down
9 changes: 7 additions & 2 deletions src/Elf/synthetic.zig
Original file line number Diff line number Diff line change
Expand Up @@ -653,13 +653,17 @@ pub const GotSection = struct {
got.next_index += 2;
}

pub inline fn getTlsLdIndex(got: GotSection) u32 {
return got.next_index;
}

pub fn size(got: GotSection) usize {
var s: usize = 0;
for (got.symbols.items) |sym| switch (sym) {
.got, .gottp => s += 8,
.tlsgd, .tlsdesc => s += 16,
};
if (got.emit_tlsld) s += 8;
if (got.emit_tlsld) s += 16;
return s;
}

Expand Down Expand Up @@ -720,6 +724,7 @@ pub const GotSection = struct {
if (got.emit_tlsld) {
if (is_shared) @panic("TODO");
try writer.writeIntLittle(u64, 1); // TODO we assume executable output here
try writer.writeIntLittle(u64, 0);
}
}

Expand Down Expand Up @@ -912,7 +917,7 @@ pub const GotSection = struct {
.st_other = 0,
.st_shndx = elf_file.got_sect_index.?,
.st_value = elf_file.getTlsLdAddress(),
.st_size = @sizeOf(u64),
.st_size = 16,
};
ilocal += 1;
}
Expand Down
54 changes: 54 additions & 0 deletions test/elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn addElfTests(b: *Build, opts: Options) *Step {
elf_step.dependOn(testTlsDso(b, opts));
elf_step.dependOn(testTlsGd(b, opts));
elf_step.dependOn(testTlsIe(b, opts));
elf_step.dependOn(testTlsLd(b, opts));
elf_step.dependOn(testTlsStatic(b, opts));
}

Expand Down Expand Up @@ -860,6 +861,59 @@ fn testTlsIe(b: *Build, opts: Options) *Step {
return test_step;
}

fn testTlsLd(b: *Build, opts: Options) *Step {
const test_step = b.step("test-elf-tls-ld", "");

const main_o = cc(b, null, opts);
main_o.addSourceBytes(
\\#include <stdio.h>
\\extern _Thread_local int foo;
\\static _Thread_local int bar;
\\int *get_foo_addr() { return &foo; }
\\int *get_bar_addr() { return &bar; }
\\int main() {
\\ bar = 5;
\\ printf("%d %d %d %d\n", *get_foo_addr(), *get_bar_addr(), foo, bar);
\\ return 0;
\\}
, "main.c");
main_o.addArgs(&.{ "-c", "-fPIC", "-ftls-model=local-dynamic" });
const main_o_out = main_o.saveOutputAs("main.o");

const a_o = cc(b, null, opts);
a_o.addSourceBytes(
\\_Thread_local int foo = 3;
, "a.c");
a_o.addArgs(&.{ "-c", "-fPIC", "-ftls-model=local-dynamic" });
const a_o_out = a_o.saveOutputAs("a.o");

const exp_stdout = "3 5 3 5\n";

{
const exe = cc(b, null, opts);
exe.addFileSource(main_o_out.file);
exe.addFileSource(a_o_out.file);
exe.addArg("-Wl,-relax");

const run = exe.run();
run.expectStdOutEqual(exp_stdout);
test_step.dependOn(run.step());
}

{
const exe = cc(b, null, opts);
exe.addFileSource(main_o_out.file);
exe.addFileSource(a_o_out.file);
exe.addArg("-Wl,-no-relax");

const run = exe.run();
run.expectStdOutEqual(exp_stdout);
test_step.dependOn(run.step());
}

return test_step;
}

fn testTlsStatic(b: *Build, opts: Options) *Step {
const test_step = b.step("test-elf-tls-static", "");

Expand Down

0 comments on commit bf984a0

Please sign in to comment.