Skip to content

Incorrect alignment assumption for emulated TLS on ARMv7 #167219

@goottime

Description

@goottime

Description

The LLVM compiler generates incorrect ARM assembly code that assumes 128-bit alignment for emulated TLS variables, when only 32-bit (4-byte) alignment is guaranteed.

Reproducer

Given the following LLVM IR:

@test = internal thread_local(localdynamic) global [64 x i8] c"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture writeonly, i8* nocapture readonly, i32, i1 immarg)
define void @testfunc() {
    %1 = alloca [64 x i8], align 1
    %a = getelementptr inbounds [64 x i8], [64 x i8]* %1, i32 0, i32 0
    %b = getelementptr inbounds [64 x i8], [64 x i8]* @test, i32 0, i32 0
    call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %b, i32 64, i1 false)
    ret void
}

Compiled with: llc -O3 -emulated-tls -mtriple=armv7-linux-gnueabihf

Actual Output

testfunc:                               @ @testfunc
        push    {r11, lr}
        sub     sp, sp, #64
        movw    r0, :lower16:__emutls_v.test
        movt    r0, :upper16:__emutls_v.test
        bl      __emutls_get_address
        vld1.64 {d16, d17}, [r0:128]!
        vld1.64 {d18, d19}, [r0:128]!
        vld1.64 {d20, d21}, [r0:128]!
        vld1.64 {d22, d23}, [r0:128]
        mov     r0, sp
        vst1.64 {d16, d17}, [r0]!
        vst1.64 {d18, d19}, [r0]!
        vst1.64 {d20, d21}, [r0]!
        vst1.64 {d22, d23}, [r0]
        add     sp, sp, #64
        pop     {r11, pc}
__emutls_v.test:
        .long   64                              @ 0x40
        .long   1                               @ 0x1
        .long   0
        .long   __emutls_t.test
__emutls_t.test:
        .zero   64,65

Problem

The generated code uses vld1.64 instructions with :128 alignment specifiers, which require 128-bit (16-byte) alignment. However, emulated TLS only guarantees 4-byte alignment on ARMv7.

From the emulated TLS implementation in compiler-rt/lib/builtins/emutls.c:

static __inline void *emutls_allocate_object(__emutls_control *control) {
  size_t size = control->size;
  size_t align = control->align;
  void *base;
  if (align < sizeof(void *))
    align = sizeof(void *);  // Only guarantees pointer-size alignment (4 bytes on ARMv7)
  // ...
}

This mismatch between assumed alignment (128-bit) and actual alignment (32-bit) will cause crashes or undefined behavior at runtime.

Expected Behavior

The compiler should either:

  • Use unaligned load instructions when emulated TLS is enabled, or
  • Ensure emulated TLS allocations meet the alignment requirements used in the generated code

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions