llvm / llvm/llvm-project

LLD COFF: .refptr. symbol placed in .text section instead of .rdata causing wrong address

Open
#194,369 0 comments 0 reactions 0 assignees View on GitHub
lld
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

## Description

When linking a COFF static library (`.a`) containing `.refptr.` symbols with LLD, the linker incorrectly places the `.refptr.` data into the `.text` code section instead of the `.rdata` data section. This causes the referenced address to be incorrectly resolved at runtime.

## Environment

- **OS**: Windows 11 Pro (MSYS2 clang64 environment)
- **LLVM version**: clang version 22.1.4 (from MSYS2 MINGW-packages)
- **LLD version**: LLD 22.1.4
- **Target**: x86_64-w64-windows-gnu

## Reproduction

### Step 1: Build a static library with clang

```bash
# Clone L-SMASH
git clone --depth=1 https://github.com/vimeo/l-smash.git /tmp/l-smash
cd /tmp/l-smash

# Configure with clang (no LTO)
./configure --prefix=/usr/local --cc=clang \
--extra-cflags="-I/usr/local/include -O3 -DNDEBUG -fno-lto -fno-pic -fno-pie" \
--extra-ldflags="-L/usr/local/lib -fno-lto -fno-pic"
make lib -j$(nproc)
make install-lib
```

### Step 2: Create a minimal test program

```c
// smoke_test.c
#include
#include
int main(void) {
lsmash_root_t *root = lsmash_create_root();
if (!root) { printf("FAIL\n"); return 1; }
printf("OK: root=%p\n", (void*)root);
lsmash_destroy_root(root);
return 0;
}
```

### Step 3: Compile and link with clang + LLD

```bash
clang -g -I/usr/local/include smoke_test.c \
/usr/local/lib/liblsmash.a /usr/local/lib/libobuparse.a -lm \
-o smoke_test.exe
./smoke_test.exe
# Result: Segmentation fault (Access violation reading 0xffffffffffffffff)
```

### Expected behavior

The program should run successfully, the same as when linked with GNU ld (binutils).

## Root cause analysis

1. In the static library, `box.o` contains a relocation:
```
000000000000ffe7 IMAGE_REL_AMD64_REL32 .refptr.isom_root_abstract_box_default
```

2. This relocation references a `.refptr.` section containing a pointer to the `isom_root_abstract_box_default` constant.

3. After linking with LLD, the `.refptr.isom_root_abstract_box_default` symbol is placed at address **0x14001149b** (inside `.text`), but the actual constant `isom_root_abstract_box_default` is at **0x14008b890** (in `.rdata`).

4. At runtime, the code executes `movq (%rip), %rcx` which loads from `0x14001149b`. The bytes at that address are `ba d8 00 00 00` (part of a `movl $0xd8, %edx` instruction), which are interpreted as the pointer value `-1` due to little-endian byte order.

5. This causes `memcpy(dst=buf, src=-1, size=0xD8)` → access violation.

## Verification

```bash
# The linked binary shows the problem:
nm smoke_test.exe | grep isom_root_abstract_box_default
# 14008b890 R isom_root_abstract_box_default <- correct address in .rdata

# But the .text references point to wrong address:
objdump -d smoke_test.exe | grep -A5 "lsmash_create_root>:"
# movq (%rip), %rcx # 0x14001149b <-- WRONG (in .text)
# The bytes at 0x14001149b are: ba d8 00 00 00 = part of "movl $0xd8, %edx"
```

## Additional notes

- **GCC + GNU ld**: Works correctly (same static library linked with GNU ld produces correct addresses)
- **clang + GNU ld**: Would work, but GNU ld is not available in MSYS2 clang64 environment
- **ThinLTO**: Does not affect the issue (occurs with and without LTO)
- This appears to be a bug in how LLD handles COFF `.refptr.` symbols from static libraries

## Tags

`lld:COFF`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.