[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