[lld] bfaec6c - [LLD][COFF] Set the Thumb bit on locally imported ARMNT function poin… (#215919)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 27 00:14:58 PDT 2026
Author: Hamed
Date: 2026-08-27T10:14:53+03:00
New Revision: bfaec6c0706706dd84582dad7bbb9f31594c0af8
URL: https://github.com/llvm/llvm-project/commit/bfaec6c0706706dd84582dad7bbb9f31594c0af8
DIFF: https://github.com/llvm/llvm-project/commit/bfaec6c0706706dd84582dad7bbb9f31594c0af8.diff
LOG: [LLD][COFF] Set the Thumb bit on locally imported ARMNT function poin… (#215919)
When a dllimport reference turns out to be locally defined, lld synthesises the
__imp_ pointer itself in LocalImportChunk. On ARMNT it was written unadjusted, so
an indirect call through the slot requests ARM state on a Thumb-only target.
Adjust it as DelayAddressChunk and AddressTableChunk already do, excluding data:
dllimport of a locally defined variable is valid and its pointer must not change.
Assisted-by: Claude Opus 5 (Anthropic)
Added:
lld/test/COFF/locally-imported-armnt.test
Modified:
lld/COFF/Chunks.cpp
Removed:
################################################################################
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index db0fde70f4511..2f2b6094fbc2c 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -951,7 +951,14 @@ void LocalImportChunk::writeTo(uint8_t *buf) const {
if (ctx.config.is64()) {
write64le(buf, sym->getRVA() + ctx.config.imageBase);
} else {
- write32le(buf, sym->getRVA() + ctx.config.imageBase);
+ uint32_t bit = 0;
+ // Pointer to thumb code must have the LSB set, so adjust it. Only code is
+ // adjusted: dllimport of a locally defined variable is valid, and the
+ // pointer to such a variable must stay unmodified.
+ if (ctx.config.machine == ARMNT && sym->getChunk() &&
+ (sym->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE))
+ bit = 1;
+ write32le(buf, (sym->getRVA() + ctx.config.imageBase) | bit);
}
}
diff --git a/lld/test/COFF/locally-imported-armnt.test b/lld/test/COFF/locally-imported-armnt.test
new file mode 100644
index 0000000000000..da8e7f99295cb
--- /dev/null
+++ b/lld/test/COFF/locally-imported-armnt.test
@@ -0,0 +1,104 @@
+## On ARMNT a locally imported function pointer must have its low bit set; a data pointer must not.
+
+# RUN: split-file %s %t.dir
+
+# RUN: yaml2obj %t.dir/code.yaml -o %t1.obj
+# RUN: lld-link /out:%t1.exe /entry:main /subsystem:console /base:0x400000 %t1.obj
+# RUN: llvm-objdump -s %t1.exe | FileCheck --check-prefix=CODE %s
+# RUN: llvm-readobj --coff-basereloc %t1.exe | FileCheck --check-prefix=CODEREL %s
+
+# CODE: Contents of section .text:
+# CODE-NEXT: 401000 704700bf 00200000
+# CODE: Contents of section .rdata:
+## Unadjusted this reads 00104000, and it is the only line here that fails without the fix.
+# CODE-NEXT: 402000 01104000
+
+# CODEREL: BaseReloc [
+# CODEREL-NEXT: Entry {
+# CODEREL-NEXT: Type: HIGHLOW
+# CODEREL-NEXT: Address: 0x2000
+# CODEREL-NEXT: }
+
+# RUN: yaml2obj %t.dir/data.yaml -o %t2.obj
+# RUN: lld-link /out:%t2.exe /entry:main /subsystem:console /base:0x400000 %t2.obj
+# RUN: llvm-objdump -s %t2.exe | FileCheck --check-prefix=DATA %s
+# RUN: llvm-readobj --coff-basereloc %t2.exe | FileCheck --check-prefix=DATAREL %s
+
+# DATA: Contents of section .text:
+# DATA-NEXT: 401000 704700bf 04200000
+# DATA: Contents of section .rdata:
+# DATA-NEXT: 402000 2a000000 00204000
+
+# DATAREL: BaseReloc [
+# DATAREL-NEXT: Entry {
+# DATAREL-NEXT: Type: HIGHLOW
+# DATAREL-NEXT: Address: 0x2004
+# DATAREL-NEXT: }
+
+#--- code.yaml
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 704700BF00000000
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: __imp_main
+ Type: IMAGE_REL_ARM_ADDR32NB
+symbols:
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_main
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
+
+#--- data.yaml
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_ARMNT
+ Characteristics: []
+sections:
+ - Name: .text
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 704700BF00000000
+ Relocations:
+ - VirtualAddress: 4
+ SymbolName: __imp_mydata
+ Type: IMAGE_REL_ARM_ADDR32NB
+ - Name: .rdata
+ Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+ Alignment: 4
+ SectionData: 2A000000
+symbols:
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: mydata
+ Value: 0
+ SectionNumber: 2
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+ - Name: __imp_mydata
+ Value: 0
+ SectionNumber: 0
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_NULL
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
More information about the llvm-commits
mailing list