我该如何将这个C程序转换为汇编代码?我很难理解这个过程或者如何开始它.我是新来的.任何帮助,将不胜感激!
while(a!=b){
if(a > b){
a = a - b;
}
else{
b = b - a;
}
}
return a;
}
Run Code Online (Sandbox Code Playgroud)
附注:假设已在寄存器R0和R1中给出了两个正整数a和b.
你能发表评论解释你是怎么做到的吗?
thu*_*zas 12
教我系统编程的教授使用他所谓的'原子C'作为C和汇编之间的垫脚石.原子C的规则是(最好的回忆):
a = b + c;不允许a = b + c + d;使用,因为那里有两个运算符.if (a < b)允许但if (( a < b) && (c < d))不允许.那么,上述计划将转化为;
label1:
if (a == b)
goto label2;
if (a < b)
goto label4;
a = a - b;
goto label3;
label4:
b = b - a;
label3:
goto label1;
label2:
return a;
Run Code Online (Sandbox Code Playgroud)
我希望我能做到这一点......自从我上次写下原子C以来已经差不多二十年了.现在假设上面的内容是正确的,让我们开始将一些原子C语句转换为MIPS(假设你正在使用的)汇编.从Elliott Frisch提供的链接,我们几乎可以立即翻译减法步骤:
a = a - b becomes R0 = R0 - R1 which is: SUBU R0, R0, R1
b = b - a becomes R1 = R1 - R0 which is: SUBU R1, R1, R0
Run Code Online (Sandbox Code Playgroud)
由于a和b都是正整数,我使用无符号减法.
比较可以这样完成:
if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2?
Run Code Online (Sandbox Code Playgroud)
这里的问题是beq操作码的第三个参数是PC移动的位移.在我们完成手工装配之前,我们不会知道这个价值.
不平等是更多的工作.如果我们遗留伪代码指令,我们首先需要使用set on less thanop代码,如果第一个寄存器小于第二个寄存器,则将其放在目标寄存器中.完成后,我们可以使用branch on equal上述内容.
if(a < b) becomes slt R2, R0, R1
goto label4 beq R2, 1, L4?
Run Code Online (Sandbox Code Playgroud)
跳转很简单,它们只是j然后跳转到的标签.所以,
goto label1 becomes j label1
Run Code Online (Sandbox Code Playgroud)
我们必须处理的最后一件事是回归.通过将我们想要的值移动到特殊寄存器V0然后在调用此函数后跳转到下一条指令来完成返回.问题是MIPS没有寄存器来注册移动命令(或者如果我忘记了它),所以我们从寄存器移到RAM然后再返回.最后,我们使用保存返回地址的特殊寄存器R31.
return a becomes var = a which is SW R0, var
ret = var which is LW var, V0
jump RA which is JR R31
Run Code Online (Sandbox Code Playgroud)
有了这些信息,程序就变成了.我们还可以调整之前不知道的跳跃:
L1:
0x0100 BEQ R0, R1, 8
0x0104 SLT R2, R0, R1 ; temp = (a < b) temp = 1 if true, 0 otherwise
0x0108 LUI R3, 0x01 ; load immediate 1 into register R3
0x010C BEQ R2, 1, 2 ; goto label4
0x0110 SUBU R0, R0, R1 ; a = a - b
0x0114 J L3 ; goto label3
L4:
0x0118 SUBU R1, R1, R0 ; b = b - a;
L3:
0x011C J L1 ; goto lable1
L2:
0x0120 SW R0, ret ; move return value from register to a RAM location
0x0123 LW ret, V0 ; move return value from RAM to the return register.
0x0124 JR R31 ; return to caller
Run Code Online (Sandbox Code Playgroud)
自从我不得不做这样的事情已经差不多二十年了(现在好几天,如果我需要汇编我只是做别人的建议,让编译器完成所有繁重的工作).我确信在此过程中我犯了一些错误,并且对于任何更正或建议都会感到高兴.我只是进入了这个冗长的讨论,因为我将OP问题解释为手工翻译 - 有人可能会在他们学习集会时这样做.
干杯.
CS *_*Pei 11
如果您正在使用gcc,则可以像gcc -S -o a.s a.c使用源代码一样获取程序集a.c.如果您使用的是Visual Studio,则可以在调试时通过选择"反汇编"窗口来获取它.这是Visual Studio的输出(我将subrountine/function命名为"common",这就是"common"出现的原因):
while(a!=b){
003613DE mov eax,dword ptr [a]
003613E1 cmp eax,dword ptr [b]
003613E4 je common+44h (0361404h)
if(a > b){
003613E6 mov eax,dword ptr [a]
003613E9 cmp eax,dword ptr [b]
003613EC jle common+39h (03613F9h)
a = a - b;
003613EE mov eax,dword ptr [a]
003613F1 sub eax,dword ptr [b]
003613F4 mov dword ptr [a],eax
}
else{
003613F7 jmp common+42h (0361402h)
b = b - a;
003613F9 mov eax,dword ptr [b]
003613FC sub eax,dword ptr [a]
003613FF mov dword ptr [b],eax
}
}
00361402 jmp common+1Eh (03613DEh)
return a;
00361404 mov eax,dword ptr [a]
}
Run Code Online (Sandbox Code Playgroud)
这里变量a最初保存在内存中,因此是b(dword ptr [b]).