是否有专门设计用于以跨平台方式进行位操作的汇编指令编译1到1的C函数或宏?

时间:2014-08-25 11:05:07

标签: c assembly arm x86-64

我有一个涉及模拟的项目(如果你查看我的帖子历史,你会看到我到底有多远!)我想要做伪二进制-translation使用C并与优化器和/或编译器一起使用C代码,将我的switch语句内容编译为单个汇编指令,主要用于非常标准的指令,例如mov s,add,{ {1}}和其他简单的位操作和算术指令。我希望同时为ARM和x86-64执行此操作,尽可能少地在两个程序集中编写。

如果我描述的东西不存在,那么我想知道是否有某种"汇编语言"我可以用来编写我的代码,然后将该程序集编译为x86-64和ARM。

3 个答案:

答案 0 :(得分:3)

如果要在运行时发出机器代码,则需要一些Just In Time translation库。您可以考虑GNU lightninglibjitLLVMGCCJITasmjit ......

你也可以(在Linux上)在某个文件中生成一些C代码,将该文件的汇编分成一个共享对象,然后dlopen(3) - 那个.so插件......

正如我评论的那样:跨平台程序集不存在且不存在(因为系统具有不同的instruction setsABI约定):考虑生成C代码,或者可能LLVM IR代码

如果您正在编写一些interpreter(其中包含许多emulators),请同时考虑threaded code种技术和bytecode代。

答案 1 :(得分:3)

要清楚地回答这一部分:

  

...然后我想知道是否有某种"汇编语言"我能   用来编写我的代码,然后将该程序集编译成x86-64和   ARM。

这正是LLVM IR所针对的目标。

  

LLVM表示旨在轻量级和低级别   同时具有表现力,类型和可扩展性。它旨在   通过处于足够低的水平,成为各种“普遍的IR”   高层次的想法可以干净地映射到它(类似于如何   微处理器是“通用IR”,允许许多源语言   要映射到他们)。

example

您可以代表此C函数

int mul_add(int x, int y, int z) {
  return x * y + z;
}

使用此LLVM IR

define i32 @mul_add(i32 %x, i32 %y, i32 %z) {
entry:
  %tmp = mul i32 %x, %y
  %tmp2 = add i32 %tmp, %z
  ret i32 %tmp2
}

答案 2 :(得分:3)

以尖锐的方式说出,#34;汇编语言"你正在谈论的是... C.

这是因为即使在不同的平台上,很多C表达式也只能直接映射到单个汇编指令。以下是部分假设,但它显示了某些C表达式可能在x86,ARM或SPARC上评估的一些指令(选择那三个因为那些是我最熟悉的):


    C code         x86 asm                   ARM asm          SPARC asm

    {              enter                     push lr          save %fp, ..., %sp
    }              leave                     pop pc           restore
    a += b;        add %ebx, %eax            add R0, R1       add %l0, %l1, %l0
    a = b + c;     lea (%ebx, %ecx), %eax    add R0, R1, R2   add %l2, %l1, %l0
    a = 0;         xor %eax, %eax            mov R0, #0       clr %l0
    a++;           inc %eax                  add R0, #1       inc %l0
    a--;           dec %eax                  sub R0, #1       dec %l0
    *ptr++;        inc (%eax)                -                -
    a = ~b;        mov %ebx, %eax; not %eax  mvn R0, R1       not %l1, %l0
    ptr = &a;      lea a, %eax               ldr R0, =a       set a, %l0
    a = b[c];      mov (%ebx, %ecx), %eax    ldr R0, [R1+R2]  ld [%l1+%l2], %l0
    (void)func();  call func                 blx func         call func
    if (a)         test %eax, %eax; jnz      tst R0, R0; bnz  tst %l0; bnz

当然,并非您可以编写为一行C代码的所有内容都将转换为单个汇编指令。如果某些多期操作可以“平坦化”,它也很大程度上取决于指令集。单个多操作数汇编指令或需要一个更原始的序列"指令。

很长一段时间以来,C编译器已经完成了'#34;中间表示"在最终转换为组装之前;这个步骤类似于现在用硬件通过x86 CPU到#34;编译"将x86组装成芯片的实际执行单元将处理的低级微操作。对LLVM IR进行编码/记录的中间层也不是那么新......因为例如Java Bytecode或Forth在概念上符合该架构。

我去C ...并查看装配输出。它不可能像现在这样紧凑,并且在相应的"化合物"操作是可用的,不可能比LLVM IR更紧凑(例如,在带有融合乘法加法的cpu上,auselen给出的示例将从LLVM IR中的三个指令开始下载。)