Lowering x64bit LLVM IR to x86bit LLVM IR

Hi,

I need some help,
As per my requirement, I am trying to lower down the x86_64bit binary LLVM IR to x86 LLVM IR.
Instruction of x86_64 binary are as follows,
mov rax, 1122334455667788
mov rax, 8877665544332211

To lower down the same in x86, I need to split ‘rax’ register into ‘rax_lower’ and ‘rax_higher’.
Can anybody please give me some pointer to do the same or any tool with option to generate the
same type of LLVM IR.

Any help will be highly appreciated.

Thanks and Regards,
Deep

Hi Sandeep,

As per my requirement, I am trying to lower down the x86_64bit binary LLVM
IR to x86 LLVM IR.
Instruction of x86_64 binary are as follows,
mov rax, 1122334455667788
mov rax, 8877665544332211
To lower down the same in x86, I need to split 'rax' register into
'rax_lower' and 'rax_higher'.

If you just want *some* code, then LLVM can take care of this itself.
You just have to compile the IR for a x86 target: "llc -mtriple=i686
..." or similar.

For example if you compile

    define i64 @foo() {
      ret i64 1122334455667788
    }

to i686, you get:

    foo:
        movl $-628319156, %eax # imm = 0xFFFFFFFFDA8C9C4C
        movl $261313, %edx # imm = 0x3FCC1
        retl

where the value obviously gets returned in eax & edx.

On the other hand, if you want the result to be compatible with real
x86 code, or even itself, you've probably got an impossible task. A
few of the big problems are:

1. Because of the differing alignment requirements struct layout will
be completely different. Code is allowed to rely on that ("malloc(N *
sizeof(type))" is a common C idiom that would break irretrievably).
2. The va_arg implementation is completely incompatible between the
two, and implemented entirely by Clang on x86_64. Varargs functions
won't work even if all code is compiled in this odd x86_64 -> x86 way.
3. The actual types used in parameter passing are different based on
the target (at least, they are on other platforms). Clang needs to
know the destination ABI to get this right and reconstructing the
intent would likely not be possible (I can't say for sure since I
haven't studied the x86 ABIs).

It all comes down to the fact that LLVM IR isn't target independent.
Clang has to know quite a lot of individual platform details to emit
its code, and they're pretty much baked in.

The PNaCl project is an effort to make a common subset work across
multiple platforms. Have you looked into whether that would fit your
needs? The output won't be compatible with the usual platform
libraries, but will with its own runtime.

Cheers.

Tim.

Hi Tim,

Thank you for this information.
I have another request for help from you,
Below is my test case,

iGetValueFromASM proc
mov rax, 5
mov rax, 5
mov rax, 2
mov rax, 5
mov rax, 2
mov rax, 112233445566
add rax, 2
mov rax, 112233445566
add rax, 5
add rax, 2

I have lowered 32bit LLVM IR,

%0 = type { i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }

define i32 @“iGetValueFromASM@#@1400037b0”(%0*) {
%2 = getelementptr inbounds %0* %0, i32 0, i32 0
%3 = getelementptr inbounds %0* %0, i32 0, i32 1
%4 = getelementptr inbounds %0* %0, i32 0, i32 21
%5 = load i32* %4, align 4
%6 = getelementptr inbounds %0* %0, i32 0, i32 24
%7 = load i32* %6, align 4
%8 = and i32 %7, -2262
%9 = add i32 %5, 14323
store i32 564295877, i32* %2, align 4
store i32 26, i32* %3, align 4
store i32 %8, i32* %6, align 4
ret i32 %9
}

This is generated with my are written. Now, I want to test this generated, lowered x64bit IR for x86bit machine.
Please let me know how I can test this. How I can test generated LLVM IR, how I can debug this generated LLVM IR.

Any help will be highly appreciated.

Regards,
Deep

This is generated with my are written. Now, I want to test this generated,
lowered x64bit IR for x86bit machine.

It looks very different from the 64-bit input, but that's a problem
for debugging to resolve I suppose.

Please let me know how I can test this. How I can test generated LLVM IR,
how I can debug this generated LLVM IR.

If it was me, I'd start with functions with well-defined inputs and
outputs (e.g. "int foo(int a, int b) { return a + b; }"). Create a
test-harness that calls out to this function and then replace the
default implementation with one that comes from your specially
converted IR. Use that to make sure the values match up.

You'd likely have difficulties with mismatched calling conventions, so
it might be better to use global variables for all input/output (so
"int a, b, res; void foo() { res = a + b; }" instead). They tend to be
easier to get working.

Cheers.

Tim.

Hi Tim,

I have implemented this engine only for opcodes that are not using memory (it is only for register to register) and currently I have lowered down LLVM IR for mov and add opcode, and thus I need to test this code only.

Is there any other way to test the same?

Thanks,
Sandeep

I have implemented this engine only for opcodes that are not using memory
(it is only for register to register) and currently I have lowered down LLVM
IR for mov and add opcode, and thus I need to test this code only.

Is there any other way to test the same?

Plenty, but only you can decide just what qualifies as working vs
broken, so I don't think we can be much help here. Just how will a
user interact with this "lowered" IR? Work that out then start off by
writing some simple examples along those lines and seeing if they
work.

Tim.