寻求有关安装和使用mips-gcc交叉编译器生成自定义ASM的帮助

时间:2014-02-27 01:44:36

标签: c gcc assembly mips cross-compiling

我正在尝试为我的自定义ISA生成程序集,类似于MIPS。我已经阅读过使用mips-gcc交叉编译器从C程序生成MIPS asm然后将其转换为我们所需的asm,但后来我无法清楚地了解它。有人请向我解释程序以及如何实现这一目标。

谢谢!!!

2 个答案:

答案 0 :(得分:2)

我假设你在谈论二进制翻译。

以此代码为例

unsigned int fun ( unsigned int a, unsigned int b, unsigned int c )
{
    return((a+b)&c);
}

假设我想使用mips C编译器,因为我没有为我的处理器编译器(在这种情况下,我将使用ARM仅用于演示目的,我们当然有ARM编译器)。 MIPS到ARM也不是一对一的事情,但对于这个简单的例子,它可以正常工作。因为ARM不使用延迟槽,所以我们要求gcc不要这样做,我们编译这个

mips-elf-gcc -O2 -c -fno-delayed-branch fun.c  -o fun.o
mips-elf-objdump -D fun.o

我当然是在作弊,你会想要链接到某个地址,我正在快速剪切并拆解该对象。您的翻译器首先阅读MIPS二进制文件,您可能或可能不希望从入口点开始预扫描指令,按照所有路径的执行顺序并记录所有分支目的地。还要隔离哪些字节是指令并假设哪些不是数据。但是,正弦mips是固定的指令长度(不是真的,有一个可以混合的16位版本)你也可以采取从一开始的方法开始并拆解所有它,你将最终拆卸数据和创建额外的工作。

所以我让gnu为我这个例子反汇编这个

00000000 <fun>:
   0:   00851021    addu    v0,a0,a1
   4:   00461024    and v0,v0,a2
   8:   03e00008    jr  ra
   c:   00000000    nop

一次只需一条指令,您的翻译工具就会分开指令(反汇编)

   0:   00851021    addu    v0,a0,a1

00000000100001010001000000100001 0x00851021
000000 00100 00101 00010 00000 100001
000000 sssss ttttt ddddd 00000 100001 addu rd,rs,rt
          r4    r5    r2

结尾
addu r2 = r4 + r5

因此我们将其直接转换为等效的

add r2,r4,r5

第二条指令

   4:   00461024    and v0,v0,a2

00000000010001100001000000100100
000000 00010 00110 00010 00000 100100
000000 sssss ttttt ddddd 00000 100100 and rd,rs,rt
       r2    r6    r2


and r2 = r2 & r6

and r2,r2,r6    

第三条指令

   8:   03e00008    jr  ra

000000 11111 000000000000000 001000 
000000 sssss 000000000000000 001000  jr rs
       r31

jr r31 or return from function

手臂

bx lr

第四条指令

          c:    00000000    nop

nop

因此,对于这四个mips指令,我们有一个直接静态二进制转换为arm

add r2,r4,r5
and r2,r2,r6    
bx lr
nop

现在你可以做两件事之一,你可以在每条指令上加上标签,然后是if / when 有一个分支,您可以分支该标签,或清洁,您可以预览所有代码 并寻找分支目的地,只标记那些。使用mips地址构建标签,以便更容易跟踪。

L00000000: add r2,r4,r5
L00000004: and r2,r2,r6    
L00000008: bx lr
L0000000C: nop

在这种情况下,我创建了arm汇编语言,我会将其输入

arm-none-eabi-as fun.s -o fun.o
arm-none-eabi-objdump -D fun.o

fun.o:     file format elf32-littlearm

Disassembly of section .text:

00000000 <L00000000>:
   0:   e0842005    add r2, r4, r5
00000004 <L00000004>:
   4:   e0022006    and r2, r2, r6
00000008 <L00000008>:
   8:   e12fff1e    bx  lr
0000000c <L0000000C>:
   c:   e1a00000    nop         ; (mov r0, r0)

我们不需要关心名为fun的标签,地址是处理器的工作方式以及如何将其编码为指令等,因此您可以使用带有上述地址的标签,它将起作用。当然,如果有任何用于分支的计算地址 目的地,或者甚至加载和存储,然后你必须在你的 翻译。

现在,如果您的新指令集与您用于编译的mips非常相似,那么您不需要进行汇编,只需将机器代码转换为机器代码,即可在一对一翻译中进行细微更改,如果它不是一对一的机器代码翻译,那么你需要创建一个伪装配器,它允许你处理标签和一对一或许多mips指令。

因为我这么远,如果你试图使用静态二进制转换来说明从MIPS转换为ARM实际上是相关的切线,你不应该在目标端使用汇编语言。使用C或您喜欢的高级语言。这使得它对任何指令集都更具可移植性(如果您正在进行此练习,则可能需要不再为另一个指令集执行此操作)。最重要的是,虽然你允许C编译器优化器为目标处理删除死代码,但是当你开始处理处理器标志时会直接转换,这样就会产生大量必须处理的死代码。

所以而不是

L00000000: add r2,r4,r5
L00000004: and r2,r2,r6
L00000008: bx lr
L0000000C: nop

如果我的目标有一个优化的C编译器,但它不是一个mips目标而且我只有一个mips二进制文件我正在翻译我没有原始的源代码然后转换为类似

...
unsigned int r2;
...
unsigned int r3;
unsigned int r4;
unsigned int r5;
unsigned int r6;
...
unsigned int PC;

switch(PC)
{
...


case L00000000: 
L00000000: 
   r2=r4+r5;
   r2=r2&r6;
   PC=0x00000008;
   break;
...
}

使用此开关附近的一些代码来管理函数调用的进入和退出。当然,还有很多我没有描述的工作。

我知道使用链接是不好的形式,但Graham Toal写了一个静态二进制翻译HOWTO,你可以谷歌搜索并希望找到http://www.gtoal.com/sbt/,希望它仍然存在。

当然如果你的指令集与mips相当接近,那你为什么不修改binutils让它编码你的指令或修改gcc让它产生汇编语言的变化?

答案 1 :(得分:1)

@dwelch已经做了相当广泛的工作来回答你的问题,但我想我会添加一点,因为我安装了MIPS交叉编译器,我认为值得向您展示如何直接从C源生成汇编

这是test.c:

int main()
{
    return -7;
}

要使用我的交叉编译器生成程序集,我会使用:mips-elf-gcc-3.4.6 test.c -S其中-S是生成程序集的标志。

这会创建一个名为test.s的文件,如下所示:

    .file   1 "test.c"
    .text
    .align  2
    .globl  main
    .ent    main
main:
    .frame  $fp,8,$31       # vars= 0, regs= 1/0, args= 0, gp= 0
    .mask   0x40000000,-8
    .fmask  0x00000000,0
    addiu   $sp,$sp,-8
    sw  $fp,0($sp)
    move    $fp,$sp
    li  $2,-7           # 0xfffffffffffffff9
    move    $sp,$fp
    lw  $fp,0($sp)
    addiu   $sp,$sp,8
    j   $31
    .end    main

为了获得额外的奖励,我们可以加快编译器的优化,以便使用mips-elf-gcc-3.4.6 test.c -S -O3进行更高效的汇编。这看起来像:

    .file   1 "test.c"
    .set    nobopt
    .text
    .align  2
    .globl  main
    .ent    main
main:
    .frame  $sp,0,$31       # vars= 0, regs= 0/0, args= 0, gp= 0
    .mask   0x00000000,0
    .fmask  0x00000000,0
    .set    noreorder
    .set    nomacro
    j   $31
    li  $2,-7           # 0xfffffffffffffff9
    .set    macro
    .set    reorder

    .end    main