将C程序转换为汇编代码
如何将这个C程序转换成汇编代码?我很难理解这个过程,甚至无法理解如何开始它。我是新来的。任何帮助都将不胜感激将C程序转换为汇编代码,c,assembly,C,Assembly,如何将这个C程序转换成汇编代码?我很难理解这个过程,甚至无法理解如何开始它。我是新来的。任何帮助都将不胜感激 while(a!=b){ if(a > b){ a = a - b; } else{ b = b - a; } } return a; } 旁注:假设寄存器R0和R1中已经给出了两个正整数a和b。 你能留下解释你是怎么做的注释吗?如果你使用的是gcc,如果你的源代码是a.c,你可以
while(a!=b){
if(a > b){
a = a - b;
}
else{
b = b - a;
}
}
return a;
}
旁注:假设寄存器R0和R1中已经给出了两个正整数a和b。你能留下解释你是怎么做的注释吗?如果你使用的是
gcc
,如果你的源代码是a.c
,你可以将程序集设置为gcc-S-o a.S a.c
。如果您使用的是Visual Studio,则可以在调试时通过选择“反汇编”窗口获得它。下面是Visual studio的输出(我将子计数器/函数命名为“common”,这就是“common”出现的原因):
这里变量
a
最初保存在内存中,b
(dword ptr[b]
)。教我系统编程的教授使用了他所谓的“原子C”作为C和汇编之间的垫脚石。原子C的规则是(据我记忆所及):
a=b+c允许使用代码>a=b+c+d不允许使用代码>,因为有两个运算符
if(a
,但不允许使用if((a
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;
我使用了无符号减法,因为a和b都是正整数
可通过以下方式进行比较:
if(a == b) goto label2 becomes if(R0 == R1) goto label2 which is: beq R0, R1, L2?
这里的问题是,beq op代码的第三个参数是PC移动的位移。在这里手工组装完成之前,我们不会知道这个值
不平等是更多的工作。如果我们离开伪代码指令,我们首先需要使用小于操作码上的设置,如果第一个寄存器小于第二个寄存器,则在目标寄存器中放入一个。完成此操作后,我们可以如上所述使用equal上的分支
if(a < b) becomes slt R2, R0, R1
goto label4 beq R2, 1, L4?
我们要处理的最后一件事是退货。返回是通过移动我们想要的值来完成的
一个特殊寄存器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
L1:
0x0100 BEQ R0、R1、8
0x0104 SLT R2、R0、R1;温度=(a
我已经有将近二十年没有做过这样的事情了(现在已经有一天了,如果我需要汇编,我就按照别人的建议去做,让编译器来完成所有繁重的工作)。我确信我在这一过程中犯了一些错误,如果有任何更正或建议,我将非常高兴。我之所以进行这种冗长的讨论,是因为我把OP问题解释为做手工翻译——有些人在学习汇编时可能会做这件事
干杯。我已将该代码翻译为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
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
尝试在这里执行代码。只需将其复制到主函数中,在循环之前定义a
和b
变量即可
您可以通过大量的解释了解代码是如何编译成汇编的,然后您可以在一个假想的CPU中执行汇编代码。虽然这是编译器的任务,但如果您想弄脏手,请查看
这是一个很棒的编译器资源管理器工具,可以让您将C/C++代码逐行转换为汇编代码
如果您是初学者,想知道“C程序如何转换为汇编?”那么我已经就此写了一篇详细的文章。使用C编译器选项生成汇编代码。请阅读以下答案:我打赌您正在学习的课程是使用MIPS汇编。你不会找到很多熟悉MIPS的专业人士。只要学习它。gcc-sfoo.c
@Oregon Trail,为什么您认为许多专业人士缺乏MIPS组装经验?如果没有别的,很多人都参加过类似的课程,或者读过MIPS作为学习汇编语言和操作系统概念的模型系统的书。谢谢!我试图理解编译器,而破解gcc或其他编译器生成的汇编代码是一件非常痛苦的事情!顺便问一下,名字重要吗?我知道我是说加载到寄存器中,但是在汇编代码中,beqa,B,8有效吗?我假设你指的是寄存器的名称。如果是的话,那么它们确实很重要。汇编程序应该在BEQ A,B,8上抛出一个错误,除非您已经将A和B定义为某物。所以,让我弄清楚,汇编指令的所有操作数名称都来自预定义的集合(表示寄存器)?i、 e.它
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
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
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