Bug ID: 41506
           Summary: Pick any COMDAT with different alignment causes
                    linking issue for Windows ARM64
           Product: lld
           Version: unspecified
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: normal
          Priority: P
         Component: COFF

LLD supports linking COFF files compiled from both Clang/LLVM and MSVC
together, both compilers could generate the same global/static data in
different alignment which only works with the respective compiler.

For example, there is a static variable in 8 bytes with type `struct _Mbstatet`
in MSVC CRT header file. Both MSVC and Clang compile this static data as COMDAT
with pick any COMDAT selection. MSVC gives it 8 bytes alignment but Clang align
it on 4 bytes. 

Both alignments work fine within each compiler. MSVC loads this 8 bytes data
via below pattern:

ADRP Xn, PageAddress            ; take page address into Xn
LDR Xt, [Xn, #imm]              ; load 8 bytes struct data

the accessing code generated by Clang looks below:

ADRP Xn, PageAddress            ; take page address into Xn 
ADD Xn, Xn, PageOffsetStaticVar ; add page offset to Xn
LDR Xt, [Xn]                    ; load 8 bytes struct data

But if linking both code patterns together, LLD/link would fail to apply
relocation for the former (MSVC) code snippet if COMDAT selection chooses the
data with 4 bytes alignment from Clang, because #imm in 64-bit LDR instruction
will be scaled by 8 bytes, so it can only load data aligned at 8 bytes. The
latter code snippet is fine because relocation happens in ADD instruction
instead of LDR instruction.

Because the code generated by MSVC and Clang make sense for themself, could
this be fixed by changing COMDAT selection to prefer the biggest alignment for
IMAGE_COMDAT_SELECT_ANY, and just for ARM64? I prototyped the change in
ObjFile::handleComdatSelection and verified it works.

below is the minimum repro code:

// header.h
typedef struct _Mbstatet {
    unsigned long _Wchar;
    unsigned short _Byte, _State;
} _Mbstatet;

class Test {
    _Mbstatet Init() {
        static _Mbstatet static_stat;
        static _Mbstatet static_stat1;

        _Mbstatet new_stat = static_stat;
        _Mbstatet new_stat1 = static_stat1;

        return new_stat1;

// t1.cpp, compile this by `clang-cl --target=arm64-windows /c /Gy /Gw /O2 /Zi
#include "header.h"

_Mbstatet bar();

_Mbstatet foo() {
    Test test;
    return test.Init();

int main() {

// t2.cpp, compile this by ARM64 MSVC, `cl /c /Gy /Gw /O2 /Zi t2.cpp`
#include "header.h"

_Mbstatet bar() {
    Test test;
    return test.Init();

Then run `lld-link.exe t1.obj t1.obj` will report following error:

lld-link: error: misaligned ldr/str offset

You are receiving this mail because:
You are on the CC list for the bug.
llvm-bugs mailing list

Reply via email to