review generic tls support

*-link.c: remove stupid loops
tccelf.c: ...also
tccgen.c: create .tdata/.tbss sections only when needed
This commit is contained in:
grischka 2026-07-08 12:47:06 +02:00
parent 7f7845cd7e
commit 5673055a9c
9 changed files with 86 additions and 213 deletions

View File

@ -434,29 +434,12 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
return; return;
case R_ARM_TLS_LE32: case R_ARM_TLS_LE32:
{ {
ElfW(Sym) *sym;
Section *sec;
int32_t x; int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1; if (s1->tls_end) {
int i; x = val - s1->tls_start + 8;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
x = val - tls_start + 8;
} else { } else {
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
Section *sec = s1->sections[sym->st_shndx];
x = val - sec->sh_addr - sec->data_offset + 8; x = val - sec->sh_addr - sec->data_offset + 8;
} }
add32le(ptr, x); add32le(ptr, x);

View File

@ -371,17 +371,8 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
return; return;
case R_AARCH64_TLSLE_ADD_TPREL_HI12: case R_AARCH64_TLSLE_ADD_TPREL_HI12:
case R_AARCH64_TLSLE_ADD_TPREL_LO12: { case R_AARCH64_TLSLE_ADD_TPREL_LO12: {
addr_t tls_start = 0;
int i;
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
}
}
/* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */ /* glibc arm64: tp points to tcbhead_t (DTV), TLS data starts after it */
int64_t tp_offset = val - tls_start + 16; int64_t tp_offset = val - s1->tls_start + 16;
int64_t imm; int64_t imm;
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12) if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
imm = (tp_offset >> 12) & 0xfff; imm = (tp_offset >> 12) & 0xfff;

View File

@ -318,31 +318,12 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
return; return;
case R_386_TLS_LE: case R_386_TLS_LE:
{ {
ElfW(Sym) *sym;
Section *sec;
int32_t x; int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1; if (s1->tls_end) {
int i; x = val - s1->tls_end;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else { } else {
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
Section *sec = s1->sections[sym->st_shndx];
x = val - sec->sh_addr - sec->data_offset; x = val - sec->sh_addr - sec->data_offset;
} }
add32le(ptr, x); add32le(ptr, x);

View File

@ -407,17 +407,7 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
case R_RISCV_TPREL_HI20: case R_RISCV_TPREL_HI20:
case R_RISCV_TPREL_LO12_I: { case R_RISCV_TPREL_LO12_I: {
addr_t tls_start = 0; int64_t tp_offset = val - s1->tls_start;
int64_t tp_offset;
int i;
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
}
}
tp_offset = val - tls_start;
if (type == R_RISCV_TPREL_HI20) { if (type == R_RISCV_TPREL_HI20) {
off64 = (int64_t)(tp_offset + 0x800) >> 12; off64 = (int64_t)(tp_offset + 0x800) >> 12;
if ((off64 + ((uint64_t)1 << 20)) >> 21) if ((off64 + ((uint64_t)1 << 20)) >> 21)

5
tcc.h
View File

@ -889,7 +889,6 @@ struct TCCState {
/* predefined sections */ /* predefined sections */
Section *text_section, *data_section, *rodata_section, *bss_section; Section *text_section, *data_section, *rodata_section, *bss_section;
Section *tdata_section, *tbss_section;
Section *common_section; Section *common_section;
Section *cur_text_section; /* current section where function code is generated */ Section *cur_text_section; /* current section where function code is generated */
#ifdef CONFIG_TCC_BCHECK #ifdef CONFIG_TCC_BCHECK
@ -930,6 +929,8 @@ struct TCCState {
ElfW_Rel *qrel; ElfW_Rel *qrel;
#define qrel s1->qrel #define qrel s1->qrel
addr_t tls_start, tls_end;
#ifdef TCC_TARGET_RISCV64 #ifdef TCC_TARGET_RISCV64
struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries; struct pcrel_hi { addr_t addr, val; } **pcrel_hi_entries;
int nb_pcrel_hi_entries; int nb_pcrel_hi_entries;
@ -1979,8 +1980,6 @@ static inline void post_sem(TCCSem *p) {
#define data_section TCC_STATE_VAR(data_section) #define data_section TCC_STATE_VAR(data_section)
#define rodata_section TCC_STATE_VAR(rodata_section) #define rodata_section TCC_STATE_VAR(rodata_section)
#define bss_section TCC_STATE_VAR(bss_section) #define bss_section TCC_STATE_VAR(bss_section)
#define tdata_section TCC_STATE_VAR(tdata_section)
#define tbss_section TCC_STATE_VAR(tbss_section)
#define common_section TCC_STATE_VAR(common_section) #define common_section TCC_STATE_VAR(common_section)
#define cur_text_section TCC_STATE_VAR(cur_text_section) #define cur_text_section TCC_STATE_VAR(cur_text_section)
#define bounds_section TCC_STATE_VAR(bounds_section) #define bounds_section TCC_STATE_VAR(bounds_section)

139
tccelf.c
View File

@ -70,8 +70,6 @@ ST_FUNC void tccelf_new(TCCState *s)
/* create ro data section (make ro after relocation done with GNU_RELRO) */ /* create ro data section (make ro after relocation done with GNU_RELRO) */
rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO); rodata_section = new_section(s, rdata, SHT_PROGBITS, shf_RELRO);
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE); bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
tdata_section = new_section(s, ".tdata", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE | SHF_TLS);
tbss_section = new_section(s, ".tbss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE | SHF_TLS);
common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE); common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
common_section->sh_num = SHN_COMMON; common_section->sh_num = SHN_COMMON;
@ -2198,12 +2196,11 @@ struct dyn_inf {
ElfW(Phdr) *phdr; ElfW(Phdr) *phdr;
int phnum; int phnum;
int shnum; int shnum;
int tls;
int relro;
Section *interp; Section *interp;
Section *note; Section *note;
Section *gnu_hash; Section *gnu_hash;
/* read only segment mapping for GNU_RELRO */
Section _roinf, *roinf;
}; };
/* Decide the layout of sections loaded in memory. This must be done before /* Decide the layout of sections loaded in memory. This must be done before
@ -2226,7 +2223,7 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
if (s->sh_flags & SHF_WRITE) if (s->sh_flags & SHF_WRITE)
j = 0x200; j = 0x200;
if (s->sh_flags & SHF_TLS) if (s->sh_flags & SHF_TLS)
j += 0x200; j = 0x300;
} else { } else {
j = 0x700; j = 0x700;
} }
@ -2287,6 +2284,9 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
sec_order[0] = 0; sec_order[0] = 0;
d->shnum = 1; d->shnum = 1;
#define SHFX_NEWPH (1 << 4)
#define SHFX_RELRO (1 << 5)
/* count PT_LOAD headers needed */ /* count PT_LOAD headers needed */
n = f0 = 0; n = f0 = 0;
for (i = 1; i < nb_sections; i++) { for (i = 1; i < nb_sections; i++) {
@ -2297,18 +2297,21 @@ static int sort_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
++d->shnum; ++d->shnum;
if (k < 0x700) { if (k < 0x700) {
f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR); f = s->sh_flags & (SHF_ALLOC|SHF_WRITE|SHF_EXECINSTR);
#if TARGETOS_NetBSD #if TARGETOS_NetBSD || TARGETOS_FreeBSD
/* NetBSD only supports 2 PT_LOAD sections. /* NetBSD only supports 2 PT_LOAD sections.
See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */ See: https://blog.netbsd.org/tnf/entry/the_first_report_on_lld */
if ((f & SHF_WRITE) == 0) if ((f & SHF_WRITE) == 0)
f |= SHF_EXECINSTR; f |= SHF_EXECINSTR;
#else #else
if ((k & 0xfff0) == 0x240) /* RELRO sections */ if ((k & 0xfff0) == 0x240) /* RELRO sections */
f |= 1<<4; d->relro = 1, f |= SHFX_RELRO;
#endif #endif
/* start new header when flags changed or relro, but avoid zero memsz */ /* start new header when flags changed or relro, but avoid zero memsz */
if (f != f0 && s->sh_size) if (f != f0 && s->sh_size)
f0 = f, ++n, f |= 1<<8; f0 = f, ++n, f |= SHFX_NEWPH;
if ((s->sh_flags & SHF_TLS) && s->sh_size)
d->tls = 1, f |= SHF_TLS;
} }
sec_cls[i] = f; sec_cls[i] = f;
//printf("ph %d sec %02d : %3X %3X %8.2X %04X %s\n", (f>0) * n, i, f, k, s->sh_type, (int)s->sh_size, s->name); //printf("ph %d sec %02d : %3X %3X %8.2X %04X %s\n", (f>0) * n, i, f, k, s->sh_type, (int)s->sh_size, s->name);
@ -2331,13 +2334,24 @@ static ElfW(Phdr) *fill_phdr(ElfW(Phdr) *ph, int type, Section *s)
return ph; return ph;
} }
static ElfW(Phdr) *update_phdr(ElfW(Phdr) *ph, int type, Section *s, addr_t addr, int file_offset)
{
if (ph->p_type == 0) {
fill_phdr(ph, type, s);
ph->p_flags |= PF_W;
}
ph->p_filesz = file_offset - ph->p_offset;
ph->p_memsz = addr - ph->p_vaddr;
return ph;
}
/* Assign sections to segments and decide how are sections laid out when loaded /* Assign sections to segments and decide how are sections laid out when loaded
in memory. This function also fills corresponding program headers. */ in memory. This function also fills corresponding program headers. */
static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d) static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
{ {
Section *s; Section *s;
addr_t addr, tmp, align, s_align, base; addr_t addr, tmp, align, s_align, base;
ElfW(Phdr) *ph = NULL; ElfW(Phdr) *ph = NULL, *ph2;
int i, f, n, phnum, phfill; int i, f, n, phnum, phfill;
int file_offset; int file_offset;
@ -2347,26 +2361,16 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
if (d->interp) if (d->interp)
phfill = 2; phfill = 2;
phnum += phfill; phnum += phfill;
if (d->tls)
d->tls = phnum, ++phnum;
if (d->relro)
d->relro = phnum, ++phnum;
if (d->note) if (d->note)
++phnum; ++phnum;
if (d->dynamic) if (d->dynamic)
++phnum; ++phnum;
if (eh_frame_hdr_section) if (eh_frame_hdr_section)
++phnum; ++phnum;
if (d->roinf)
++phnum;
{
int has_tls = 0;
for (i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_flags & SHF_TLS) {
has_tls = 1;
break;
}
}
if (has_tls)
++phnum;
}
d->phnum = phnum; d->phnum = phnum;
d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr))); d->phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
@ -2415,7 +2419,7 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
continue; continue;
} }
if ((f & 1<<8) && n) { if ((f & SHFX_NEWPH) && n) {
/* different rwx section flags */ /* different rwx section flags */
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) { if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
/* if in the middle of a page, w e duplicate the page in /* if in the middle of a page, w e duplicate the page in
@ -2433,51 +2437,53 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
s->sh_offset = file_offset; s->sh_offset = file_offset;
s->sh_addr = addr; s->sh_addr = addr;
if (f & 1<<8) { addr += s->sh_size;
if (s->sh_type != SHT_NOBITS)
file_offset += s->sh_size;
if (f & SHFX_NEWPH) {
/* set new program header */ /* set new program header */
ph = &d->phdr[phfill + n]; ph = &d->phdr[phfill + n];
ph->p_type = PT_LOAD; fill_phdr(ph, PT_LOAD, s);
ph->p_align = s_align; ph->p_align = s_align;
ph->p_flags = PF_R;
if (f & SHF_WRITE) if (f & SHF_WRITE)
ph->p_flags |= PF_W; ph->p_flags |= PF_W;
if (f & SHF_EXECINSTR) if (f & SHF_EXECINSTR)
ph->p_flags |= PF_X; ph->p_flags |= PF_X;
ph->p_offset = file_offset;
ph->p_vaddr = addr;
if (n == 0) { if (n == 0) {
/* Make the first PT_LOAD segment include the program /* Make the first PT_LOAD segment include the program
headers itself (and the ELF header as well), it'll headers itself (and the ELF header as well), it'll
come out with same memory use but will make various come out with same memory use but will make various
tools like binutils strip work better. */ tools like binutils strip work better. */
ph->p_offset = 0; ph->p_offset = 0;
ph->p_vaddr = base; ph->p_paddr = ph->p_vaddr = base;
} }
ph->p_paddr = ph->p_vaddr;
++n; ++n;
} }
if (f & 1<<4) { if (ph)
Section *roinf = &d->_roinf; update_phdr(ph, 0, 0, addr, file_offset);
if (roinf->sh_size == 0) {
roinf->sh_offset = s->sh_offset; if (f & SHFX_RELRO) {
roinf->sh_addr = s->sh_addr; ph2 = update_phdr(&d->phdr[d->relro], PT_GNU_RELRO, s, addr, file_offset);
roinf->sh_addralign = 1; ph2->p_align = 1;
}
roinf->sh_size = (addr - roinf->sh_addr) + s->sh_size;
} }
addr += s->sh_size; if (f & SHF_TLS) {
if (s->sh_type != SHT_NOBITS) ph2 = update_phdr(&d->phdr[d->tls], PT_TLS, s, addr, file_offset);
file_offset += s->sh_size; if (s->sh_addralign > ph2->p_align)
ph2->p_align = s->sh_addralign;
if (ph) {
ph->p_filesz = file_offset - ph->p_offset;
ph->p_memsz = addr - ph->p_vaddr;
} }
} }
if (d->tls) {
++ph;
/* for xxx-link.c:relocate() */
s1->tls_start = ph->p_vaddr;
s1->tls_end = s1->tls_start + ph->p_memsz + (-ph->p_memsz & (ph->p_align - 1));
}
if (d->relro)
++ph;
/* Fill other headers */ /* Fill other headers */
if (d->note) if (d->note)
fill_phdr(++ph, PT_NOTE, d->note); fill_phdr(++ph, PT_NOTE, d->note);
@ -2485,36 +2491,6 @@ static int layout_sections(TCCState *s1, int *sec_order, struct dyn_inf *d)
fill_phdr(++ph, PT_DYNAMIC, d->dynamic)->p_flags |= PF_W; fill_phdr(++ph, PT_DYNAMIC, d->dynamic)->p_flags |= PF_W;
if (eh_frame_hdr_section) if (eh_frame_hdr_section)
fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section); fill_phdr(++ph, PT_GNU_EH_FRAME, eh_frame_hdr_section);
if (d->roinf)
fill_phdr(++ph, PT_GNU_RELRO, d->roinf)->p_flags |= PF_W;
{
/* Create PT_TLS segment covering all TLS sections */
Section *tls_start_sec = NULL;
addr_t tls_start = 0, tls_end = 0;
for (i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start_sec) {
tls_start_sec = s;
tls_start = s->sh_addr;
tls_end = s->sh_addr + s->sh_size;
} else {
if (s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
}
}
}
if (tls_start_sec) {
ph = fill_phdr(++ph, PT_TLS, tls_start_sec);
ph->p_vaddr = tls_start;
ph->p_paddr = tls_start;
ph->p_filesz = tls_end - tls_start;
ph->p_memsz = ph->p_filesz;
ph->p_align = tls_start_sec->sh_addralign;
}
}
if (d->interp) if (d->interp)
fill_phdr(&d->phdr[1], PT_INTERP, d->interp); fill_phdr(&d->phdr[1], PT_INTERP, d->interp);
if (phfill) { if (phfill) {
@ -2823,7 +2799,7 @@ static void reorder_sections(TCCState *s1, int *sec_order)
backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0])); backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0]));
for (i = 0, nnew = 0, snew = NULL; i < s1->nb_sections; i++) { for (i = 0, nnew = 0, snew = NULL; i < s1->nb_sections; i++) {
k = sec_order[i]; k = sec_order ? sec_order[i] : i;
s = s1->sections[k]; s = s1->sections[k];
if (!i || s->sh_name) { if (!i || s->sh_name) {
backmap[k] = nnew; backmap[k] = nnew;
@ -2986,7 +2962,6 @@ static int elf_output_file(TCCState *s1, const char *filename)
ret = -1; ret = -1;
interp = dynstr = dynamic = NULL; interp = dynstr = dynamic = NULL;
sec_order = NULL; sec_order = NULL;
dyninf.roinf = &dyninf._roinf;
#ifdef TCC_TARGET_ARM #ifdef TCC_TARGET_ARM
create_arm_attribute_section (s1); create_arm_attribute_section (s1);
@ -3008,10 +2983,6 @@ static int elf_output_file(TCCState *s1, const char *filename)
dyninf.note = create_bsd_note_section (s1, ".note.tag", "FreeBSD"); dyninf.note = create_bsd_note_section (s1, ".note.tag", "FreeBSD");
#endif #endif
#if TARGETOS_FreeBSD || TARGETOS_NetBSD
dyninf.roinf = NULL;
#endif
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */ /* if linking, also link in runtime libraries (libc, libgcc, etc.) */
tcc_add_runtime(s1); tcc_add_runtime(s1);
resolve_common_syms(s1); resolve_common_syms(s1);

View File

@ -8400,10 +8400,9 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY)) while ((tp->t & (VT_BTYPE|VT_ARRAY)) == (VT_PTR|VT_ARRAY))
tp = &tp->ref->type; tp = &tp->ref->type;
if (type->t & VT_TLS) { if (type->t & VT_TLS) {
if (has_init) sec = find_section(tcc_state, has_init ? ".tdata" : ".tbss");
sec = tdata_section; sec->sh_flags = SHF_ALLOC | SHF_WRITE | SHF_TLS;
else sec->sh_type = has_init ? SHT_PROGBITS : SHT_NOBITS;
sec = tbss_section;
} else if (tp->t & VT_CONSTANT) { } else if (tp->t & VT_CONSTANT) {
sec = rodata_section; sec = rodata_section;
} else if (has_init) { } else if (has_init) {

View File

@ -57,8 +57,8 @@ endif
ifeq ($(CONFIG_OSX),yes) ifeq ($(CONFIG_OSX),yes)
SKIP += 144_tls.test # TLS runtime not supported on Mach-O SKIP += 144_tls.test # TLS runtime not supported on Mach-O
endif endif
ifeq (,$(filter i386 x86_64 riscv64 arm64,$(ARCH))) ifeq (-$(ARCH)-,-arm-)
SKIP += 144_tls.test # TLS only implemented on these architectures so far SKIP += 144_tls.test # doesn't work currently
endif endif
ifneq (-$(ARCH)-,-arm64-) ifneq (-$(ARCH)-,-arm64-)
SKIP += 138_arm64_encoding.test SKIP += 138_arm64_encoding.test

View File

@ -368,70 +368,29 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
tcc_error_noabort("unexpected R_X86_64_TLSLD pattern"); tcc_error_noabort("unexpected R_X86_64_TLSLD pattern");
} }
break; break;
case R_X86_64_DTPOFF32: case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32: case R_X86_64_TPOFF32:
{
ElfW(Sym) *sym;
Section *sec;
int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1;
int i;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else {
x = val - sec->sh_addr - sec->data_offset;
}
add32le(ptr, x);
}
break;
case R_X86_64_DTPOFF64: case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64: case R_X86_64_TPOFF64:
{ {
ElfW(Sym) *sym;
Section *sec;
int32_t x; int32_t x;
addr_t tls_start = 0, tls_end = 0, tls_align = 1; if (s1->tls_end) {
int i; x = val - s1->tls_end;
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
sec = s1->sections[sym->st_shndx];
for (i = 1; i < s1->nb_sections; i++) {
Section *s = s1->sections[i];
if (s->sh_flags & SHF_TLS && s->sh_size) {
if (!tls_start || s->sh_addr < tls_start)
tls_start = s->sh_addr;
if (s->sh_addr + s->sh_size > tls_end)
tls_end = s->sh_addr + s->sh_size;
if (s->sh_addralign > tls_align)
tls_align = s->sh_addralign;
}
}
if (tls_end > tls_start) {
addr_t tls_size = tls_end - tls_start;
addr_t aligned_size = (tls_size + tls_align - 1) & ~(tls_align - 1);
x = val - (tls_start + aligned_size);
} else { } else {
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
Section *sec = s1->sections[sym->st_shndx];
x = val - sec->sh_addr - sec->data_offset; x = val - sec->sh_addr - sec->data_offset;
} }
add64le(ptr, x); switch (type) {
case R_X86_64_DTPOFF64:
case R_X86_64_TPOFF64:
add64le(ptr, x);
break;
default:
add32le(ptr, x);
break;
}
} }
break; break;
case R_X86_64_NONE: case R_X86_64_NONE: