我如何将此C程序转换为汇编代码?我很难理解这个过程或者如何开始它。我是新来的。任何帮助将不胜感激!
while(a!=b){
if(a > b){
a = a - b;
}
else{
b = b - a;
}
}
return a;
}
侧注:假设已在寄存器R0和R1中给出了两个正整数a和b 你能留下评论解释你是怎么做到的吗?
答案 0 :(得分:10)
如果您使用的是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]
}
此处变量a
最初保存在内存中,因此b
(dword ptr [b]
)。
答案 1 :(得分:9)
教我系统编程的教授使用了他所谓的原子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;
我希望我能做到这一点......自从我上次写下原子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
我使用无符号减法,因为a和b都是正整数。
比较可以这样做:
if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2?
这里的问题是beq操作码的第三个参数是PC移动的位移。在我们完成手工装配之前,我们不会知道这个价值。
不平等是更多的工作。如果我们遗留伪代码指令,我们首先需要使用set on less than
操作码,如果第一个寄存器小于第二个寄存器,则将其放在目标寄存器中。完成后,我们可以使用上面描述的branch on equal
。
if(a < b) becomes slt R2, R0, R1
goto label4 beq R2, 1, L4?
跳转很简单,它们只是j然后跳转到的标签。所以,
goto label1 becomes j label1
我们必须处理的最后一件事是返回。返回是通过移动我们想要的值来完成的 一个特殊的寄存器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
有了这些信息,程序就变成了。我们还可以调整之前我们不知道的跳跃:
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
我已经差不多二十年了,因为我必须做这样的事情(现在好几天,如果我需要组装,我只是做别人建议的事情,让编译器完成所有繁重的工作)。我确信在此过程中我犯了一些错误,并且会对任何更正或建议感到高兴。我只是进入了这个冗长的讨论,因为我将OP问题解释为手工翻译 - 有人在学习装配时可能会这样做。
欢呼声。
答案 2 :(得分:1)
我已将该代码转换为16位NASM程序集:
loop:
cmp ax, bx
je .end; if A is not equal to B, then continue executing. Else, exit the loop
jg greater_than; if A is greater than B...
sub ax, bx; ... THEN subtract B from A...
jmp loop; ... and loop back to the beginning!
.greater_than:
sub bx, ax; ... ELSE, subtract A from B...
jmp loop; ... and loop back to the beginning!
.end:
push ax; return A
我使用ax
代替r0
和bx
代替r1
答案 3 :(得分:0)
ORG 000H // origin
MOV DPTR,#LUT // moves starting address of LUT to DPTR
MOV P1,#00000000B // sets P1 as output port
MOV P0,#00000000B // sets P0 as output port
MAIN: MOV R6,#230D // loads register R6 with 230D
SETB P3.5 // sets P3.5 as input port
MOV TMOD,#01100001B // Sets Timer1 as Mode2 counter & Timer0 as Mode1 timer
MOV TL1,#00000000B // loads TL1 with initial value
MOV TH1,#00000000B // loads TH1 with initial value
SETB TR1 // starts timer(counter) 1
BACK: MOV TH0,#00000000B // loads initial value to TH0
MOV TL0,#00000000B // loads initial value to TL0
SETB TR0 // starts timer 0
HERE: JNB TF0,HERE // checks for Timer 0 roll over
CLR TR0 // stops Timer0
CLR TF0 // clears Timer Flag 0
DJNZ R6,BACK
CLR TR1 // stops Timer(counter)1
CLR TF0 // clears Timer Flag 0
CLR TF1 // clears Timer Flag 1
ACALL DLOOP // Calls subroutine DLOOP for displaying the count
SJMP MAIN // jumps back to the main loop
DLOOP: MOV R5,#252D
BACK1: MOV A,TL1 // loads the current count to the accumulator
MOV B,#4D // loads register B with 4D
MUL AB // Multiplies the TL1 count with 4
MOV B,#100D // loads register B with 100D
DIV AB // isolates first digit of the count
SETB P1.0 // display driver transistor Q1 ON
ACALL DISPLAY // converts 1st digit to 7seg pattern
MOV P0,A // puts the pattern to port 0
ACALL DELAY
ACALL DELAY
MOV A,B
MOV B,#10D
DIV AB // isolates the second digit of the count
CLR P1.0 // display driver transistor Q1 OFF
SETB P1.1 // display driver transistor Q2 ON
ACALL DISPLAY // converts the 2nd digit to 7seg pattern
MOV P0,A
ACALL DELAY
ACALL DELAY
MOV A,B // moves the last digit of the count to accumulator
CLR P1.1 // display driver transistor Q2 OFF
SETB P1.2 // display driver transistor Q3 ON
ACALL DISPLAY // converts 3rd digit to 7seg pattern
MOV P0,A // puts the pattern to port 0
ACALL DELAY // calls 1ms delay
ACALL DELAY
CLR P1.2
DJNZ R5,BACK1 // repeats the subroutine DLOOP 100 times
MOV P0,#11111111B
RET
DELAY: MOV R7,#250D // 1ms delay
DEL1: DJNZ R7,DEL1
RET
DISPLAY: MOVC A,@A+DPTR // gets 7seg digit drive pattern for current value in A
CPL A
RET
LUT: DB 3FH // LUT starts here
DB 06H
DB 5BH
DB 4FH
DB 66H
DB 6DH
DB 7DH
DB 07H
DB 7FH
DB 6FH
END
答案 4 :(得分:0)
尝试在此处执行代码。只需将其复制到main函数中,在a
循环之前定义b
和while
变量,就可以了。
您可以通过大量解释了解如何将代码编译为汇编代码,然后您可以在假设的CPU内执行汇编代码。
答案 5 :(得分:0)