mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
feat(arm64): add TLS Local Exec code generation and linker relocations
This commit is contained in:
parent
11f5c6e1f9
commit
8abaf10ab5
49
arm64-gen.c
49
arm64-gen.c
@ -552,6 +552,23 @@ ST_FUNC void load(int r, SValue *sv)
|
||||
}
|
||||
|
||||
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
|
||||
if (sv->sym->type.t & VT_TLS) {
|
||||
o(0xd53bd05e); /* mrs x30, tpidr_el0 */
|
||||
greloca(cur_text_section, sv->sym, ind,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
|
||||
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) |
|
||||
ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0, lsl #12 */
|
||||
greloca(cur_text_section, sv->sym, ind,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
|
||||
o(ARM64_ADD_IMM | ARM64_SF(1) |
|
||||
ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0 */
|
||||
if (IS_FREG(r))
|
||||
arm64_ldrv(arm64_type_size(svtt), fltr(r), 30, svcoff);
|
||||
else
|
||||
arm64_ldrx(!(svtt&VT_UNSIGNED), arm64_type_size(svtt),
|
||||
intr(r), 30, svcoff);
|
||||
return;
|
||||
}
|
||||
arm64_sym(30, sv->sym, // use x30 for address
|
||||
arm64_check_offset(0, arm64_type_size(svtt), svcoff));
|
||||
if (IS_FREG(r))
|
||||
@ -645,6 +662,22 @@ ST_FUNC void store(int r, SValue *sv)
|
||||
if (svr == (VT_CONST | VT_LVAL)) {
|
||||
uint64_t i = sv->c.i;
|
||||
|
||||
if (sv->sym && (sv->sym->type.t & VT_TLS)) {
|
||||
o(0xd53bd05e);
|
||||
greloca(cur_text_section, sv->sym, ind,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
|
||||
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) |
|
||||
ARM64_RN(30) | ARM64_RD(30));
|
||||
greloca(cur_text_section, sv->sym, ind,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
|
||||
o(ARM64_ADD_IMM | ARM64_SF(1) |
|
||||
ARM64_RN(30) | ARM64_RD(30));
|
||||
if (IS_FREG(r))
|
||||
arm64_strv(arm64_type_size(svtt), fltr(r), 30, i);
|
||||
else
|
||||
arm64_strx(arm64_type_size(svtt), intr(r), 30, i);
|
||||
return;
|
||||
}
|
||||
if (sv->sym)
|
||||
arm64_sym(30, sv->sym, // use x30 for address
|
||||
arm64_check_offset(0, arm64_type_size(svtt), i));
|
||||
@ -668,6 +701,22 @@ ST_FUNC void store(int r, SValue *sv)
|
||||
}
|
||||
|
||||
if (svr == (VT_CONST | VT_LVAL | VT_SYM)) {
|
||||
if (sv->sym->type.t & VT_TLS) {
|
||||
o(0xd53bd05e); /* mrs x30, tpidr_el0 */
|
||||
greloca(cur_text_section, sv->sym, ind,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_HI12, 0);
|
||||
o(ARM64_ADD_IMM | ARM64_SF(1) | ARM64_SH(1) |
|
||||
ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0, lsl #12 */
|
||||
greloca(cur_text_section, sv->sym, ind,
|
||||
R_AARCH64_TLSLE_ADD_TPREL_LO12, 0);
|
||||
o(ARM64_ADD_IMM | ARM64_SF(1) |
|
||||
ARM64_RN(30) | ARM64_RD(30)); /* add x30, x30, #0 */
|
||||
if (IS_FREG(r))
|
||||
arm64_strv(arm64_type_size(svtt), fltr(r), 30, svcoff);
|
||||
else
|
||||
arm64_strx(arm64_type_size(svtt), intr(r), 30, svcoff);
|
||||
return;
|
||||
}
|
||||
arm64_sym(30, sv->sym, // use x30 for address
|
||||
arm64_check_offset(0, arm64_type_size(svtt), svcoff));
|
||||
if (IS_FREG(r))
|
||||
|
||||
25
arm64-link.c
25
arm64-link.c
@ -43,6 +43,8 @@ ST_FUNC int code_reloc (int reloc_type)
|
||||
case R_AARCH64_LDST32_ABS_LO12_NC:
|
||||
case R_AARCH64_LDST16_ABS_LO12_NC:
|
||||
case R_AARCH64_LDST8_ABS_LO12_NC:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
|
||||
case R_AARCH64_GLOB_DAT:
|
||||
case R_AARCH64_COPY:
|
||||
return 0;
|
||||
@ -80,6 +82,8 @@ ST_FUNC int gotplt_entry_type (int reloc_type)
|
||||
case R_AARCH64_COPY:
|
||||
case R_AARCH64_CONDBR19:
|
||||
case R_AARCH64_TSTBR14:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12:
|
||||
return NO_GOTPLT_ENTRY;
|
||||
|
||||
case R_AARCH64_ABS32:
|
||||
@ -365,6 +369,27 @@ ST_FUNC void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr,
|
||||
#endif
|
||||
write64le(ptr, val - rel->r_addend);
|
||||
return;
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
||||
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 */
|
||||
int64_t tp_offset = val - tls_start + 16;
|
||||
int64_t imm;
|
||||
if (type == R_AARCH64_TLSLE_ADD_TPREL_HI12)
|
||||
imm = (tp_offset >> 12) & 0xfff;
|
||||
else
|
||||
imm = tp_offset & 0xfff;
|
||||
write32le(ptr, ((read32le(ptr) & 0xffc003ff) | (imm << 10)));
|
||||
return;
|
||||
}
|
||||
case R_AARCH64_RELATIVE:
|
||||
#ifdef TCC_TARGET_PE
|
||||
add32le(ptr, val - s1->pe_imagebase);
|
||||
|
||||
@ -19,7 +19,7 @@ ifeq (,$(filter i386 x86_64,$(ARCH)))
|
||||
SKIP += 85_asm-outside-function.test # x86 asm
|
||||
SKIP += 127_asm_goto.test # hardcodes x86 asm
|
||||
endif
|
||||
ifeq (,$(filter x86_64 riscv64,$(ARCH)))
|
||||
ifeq (,$(filter x86_64 riscv64 arm64,$(ARCH)))
|
||||
SKIP += 144_tls.test # TLS only implemented on x86_64 so far
|
||||
endif
|
||||
ifeq ($(CONFIG_backtrace),no)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user