Skip to content

Commit

Permalink
elf: handle large and multiple TLS zerofill sections
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Jul 21, 2023
1 parent 16dacd4 commit 88731e9
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
16 changes: 11 additions & 5 deletions src/Elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1059,6 +1059,8 @@ pub inline fn shdrIsTls(shdr: *const elf.Elf64_Shdr) bool {
}

fn allocateSectionsInMemory(self: *Elf, base_offset: u64) !void {
const shdrs = self.sections.slice().items(.shdr);

// We use this struct to track maximum alignment of all TLS sections.
// According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold,
// in-file offsets have to be aligned against the start of TLS program header.
Expand All @@ -1080,29 +1082,33 @@ fn allocateSectionsInMemory(self: *Elf, base_offset: u64) !void {
};

var alignment = Align{};
for (self.sections.items(.shdr)[1..], 1..) |*shdr, shndx| {
for (shdrs[1..], 1..) |*shdr, shndx| {
if (!shdrIsTls(shdr)) continue;
if (alignment.first_tls_shndx == null) alignment.first_tls_shndx = @as(u16, @intCast(shndx));
alignment.tls_start_align = @max(alignment.tls_start_align, shdr.sh_addralign);
}

var addr = self.options.image_base + base_offset;
outer: for (self.sections.items(.shdr)[1..], 1..) |*shdr, i| {
var i: u32 = 1;
while (i < shdrs.len) : (i += 1) {
const shdr = &shdrs[i];
if (!shdrIsAlloc(shdr)) continue;
if (i != 1) {
const prev_shdr = self.sections.items(.shdr)[i - 1];
const prev_shdr = shdrs[i - 1];
if (shdrToPhdrFlags(shdr.sh_flags) != shdrToPhdrFlags(prev_shdr.sh_flags)) {
// We need advance by page size
addr += self.options.page_size.?;
}
}
if (shdrIsTbss(shdr)) {
var tbss_addr = addr;
for (self.sections.items(.shdr)[i..]) |*tbss_shdr| {
if (!shdrIsTbss(tbss_shdr)) continue :outer;
while (true) {
const tbss_shdr = &shdrs[i];
tbss_addr = alignment.@"align"(@as(u16, @intCast(i)), shdr.sh_addralign, tbss_addr);
tbss_shdr.sh_addr = tbss_addr;
tbss_addr += tbss_shdr.sh_size;
if (i + 1 >= shdrs.len or !shdrIsTbss(&shdrs[i + 1])) break;
i += 1;
}
}

Expand Down
32 changes: 32 additions & 0 deletions test/elf.zig
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub fn addElfTests(b: *Build, opts: Options) *Step {
elf_step.dependOn(testTlsGdToIe(b, opts));
elf_step.dependOn(testTlsIe(b, opts));
elf_step.dependOn(testTlsLargeAlignment(b, opts));
elf_step.dependOn(testTlsLargeTbss(b, opts));
elf_step.dependOn(testTlsLargeStaticImage(b, opts));
elf_step.dependOn(testTlsLd(b, opts));
elf_step.dependOn(testTlsLdDso(b, opts));
Expand Down Expand Up @@ -2550,6 +2551,37 @@ fn testTlsLargeAlignment(b: *Build, opts: Options) *Step {
return test_step;
}

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

const exe = cc(b, opts);
exe.addAsmSource(
\\.globl x, y
\\.section .tbss,"awT",@nobits
\\x:
\\.zero 1024
\\.section .tcommon,"awT",@nobits
\\y:
\\.zero 1024
);
exe.addCSource(
\\#include <stdio.h>
\\extern _Thread_local char x[1024000];
\\extern _Thread_local char y[1024000];
\\int main() {
\\ x[0] = 3;
\\ x[1023] = 5;
\\ printf("%d %d %d %d %d %d\n", x[0], x[1], x[1023], y[0], y[1], y[1023]);
\\}
);

const run = exe.run();
run.expectStdOutEqual("3 0 5 0 0 0\n");
test_step.dependOn(run.step());

return test_step;
}

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

Expand Down

0 comments on commit 88731e9

Please sign in to comment.