ldc-developers / ldc

The LLVM-based D Compiler.
http://wiki.dlang.org/LDC
Other
1.21k stars 261 forks source link

Bug with mov/lea in inline assembler #3963

Open sr-tream opened 2 years ago

sr-tream commented 2 years ago

Code:

import std.stdio;

extern (C)
{
    __gshared int xversion = 43;

    export int asm_test()
    {
        asm
        {
            naked;
            mov RAX, xversion;
            // lea RAX, xversion;
            // mov EAX, [RAX]; // also - crash
            ret;
        }
    }
}

void main()
{
    asm_test().writeln;
}

This code can be compiled only for Windows x86_64! On Linux, compilation failed with PIC error.

Base image address - 0x140000000

This code after compilation use invalid address of xversion - it reduces address to 4byte, but not use RIP-relative access. Instead of mov RAX, [0x1400a1000] generated mov RAX, [0x400a1000]. Some bug with lea

Code on C++ work fine:

#include <iostream>
#include <ostream>

extern "C" {
    static auto xversion = 43;

    int asm_test() __attribute__((naked));

    int asm_test(){
        __asm{
            mov RAX, xversion;
            ret;
        }
    }
}

int main(){
    std:: cout << asm_test() << std::endl;
    return 0;
}

Compiled with clang++ -fms-extensions. Flag -fms-extensions used to write asm with intal syntax, like on D.

Clang version - 13.0.1 ldc2 version - 1.28.1 (based on DMD v2.098.1 and LLVM 13.0.1)

P.S. dmd can't compile this code on x86_64.

P.P.S. rizin can compile this instruction properly - 0x00000000 10 48a100100a4001000000 movabs rax, qword [0x1400a1000]

JohanEngelen commented 2 years ago

On Windows, you can probably make it work with [RIP + xversion] instead of xversion. https://d.godbolt.org/z/WTafs6Tbv

On Linux with PIC, it's not so easy: https://d.godbolt.org/z/bbrTE76h1

Does clang++ create a PIC executable?

kinke commented 2 years ago

Note that this only applies to naked DMD-style inline asm. This can also be expressed in non-naked DMD asm, but still making the function naked (and so I guess analogous to your clang example):

import ldc.attributes;
export int asm_test2() @naked
{
    asm
    {
        mov RAX, xversion;
        ret;
    }
}