Skip to content

[x86] Implement R_X86_64_GOTTPOFF IE→LE TLS relaxation#1547

Open
Saharsh Burra (bsaharsh) wants to merge 1 commit into
qualcomm:mainfrom
bsaharsh:relaxation/TLS-IE-LE
Open

[x86] Implement R_X86_64_GOTTPOFF IE→LE TLS relaxation#1547
Saharsh Burra (bsaharsh) wants to merge 1 commit into
qualcomm:mainfrom
bsaharsh:relaxation/TLS-IE-LE

Conversation

@bsaharsh

Copy link
Copy Markdown
Contributor

Implements IE→LE TLS relaxation for R_X86_64_GOTTPOFF relocations.

For non-preemptible symbols in executables, GOTTPOFF GOT-indirect accesses
are rewritten in-place to direct TP-relative immediates when:

  • The symbol is non-preemptible and the output is an executable (static,
    dynamic, or PIE)
  • The link is not partial (-r)

All MOV and ADD sub-cases are handled (7→7 bytes, size-preserving). %rsp
and %r12 use addq $imm instead of leaq since leaq would need a SIB byte
(8 bytes).

IE→LE is mandatory and fires regardless of --relax, matching lld and bfd.
Without this relaxation, the GOT slot and R_X86_64_TPOFF64 dynamic
relocation are unnecessarily kept in executables.

Note: This PR contains two commits. The first ([x86] Support
R_X86_64_GOTPCRELX relaxation) is a dependency.

Tests:

TLSIERelax_StaticMov
TLSIERelax_StaticAdd
TLSIERelax_StaticAddRsp
TLSIERelax_ExecNonPreemptible
TLSIERelax_SharedKeepsGOT
TLSIERelax_AddendNonM4
TLSIERelax_PartialRelink
TLSIERelax_Trace

Fixes #1511

For non-preemptible symbols in executables (static, dynamic, or PIE),
rewrite GOTTPOFF GOT-indirect accesses to direct TP-relative immediates:

  48 8b 05 [rel32]   movq  sym@gottpoff(%rip), %rax  ->  movq  $tpoff, %rax
  48 03 05 [rel32]   addq  sym@gottpoff(%rip), %rax  ->  leaq  tpoff(%rax), %rax
  48 03 25 [rel32]   addq  sym@gottpoff(%rip), %rsp  ->  addq  $tpoff, %rsp

All six MOV/ADD sub-cases are 7→7 bytes (size-preserving). %rsp and %r12
use addq $imm instead of leaq, which would need a SIB byte (8 bytes).

This eliminates one IE GOT slot (8 bytes), the R_X86_64_TPOFF64 dynamic
relocation (in non-static executable links), and one runtime memory load
per TLS access.

Relaxation fires when:
- The symbol is non-preemptible and the output is an executable (static,
  dynamic, or PIE) — LE requires the variable's TP-relative offset to be
  a link-time constant, which holds only for the executable's own block
- The link is not partial (-r)

IE→LE is a mandatory ABI TLS transition and fires regardless of --relax,
matching lld and bfd. The --relax flag governs optional relaxations
(e.g. GOTPCRELX). Shared libraries are never relaxed even for hidden
symbols — the loader places the DSO TLS block at a runtime-determined
offset.

Approach
--------
- Scan: shouldRelaxTLSIEToLE() combines isTLSIERelaxable() (addend == -4,
  MOV/ADD opcode, RegionFragment) with the non-preemptible-in-executable
  condition. Qualifying GOTTPOFF relocations skip GOT creation and are
  recorded as candidates.

- postProcessing: the IE→LE candidate loop always runs (mandatory).
  relaxTLSIEReloc() patches the REX/opcode/ModR/M bytes and writes the
  immediate.

- Apply: relocGOTRelative early-returns OK for candidates, whose bytes are
  already rewritten and which have no GOT slot to reference.

- --trace=relax emits trace_relax_gottpoff for each relaxed reference.

Link modes
----------
IE→LE applies to static, dynamic, and PIE executables for non-preemptible
symbols. Shared objects and preemptible symbols keep the GOT slot with the
R_X86_64_TPOFF64 dynamic reloc. Partial links (-r) are never relaxed.

Tests:
- TLSIERelax_StaticMov
- TLSIERelax_StaticAdd
- TLSIERelax_StaticAddRsp
- TLSIERelax_ExecNonPreemptible
- TLSIERelax_SharedKeepsGOT
- TLSIERelax_AddendNonM4
- TLSIERelax_PartialRelink
- TLSIERelax_Trace

Fixes qualcomm#1511

Signed-off-by: bsaharsh <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TLS IE→LE relaxation not implemented in x86

1 participant