下面我尝试在32位汇编中实现的C ++代码如下:
for(int ebx = 3; ebx < 10; ebx++){
print("LO");
for(int esi = 2; esi < ebx; esi++){
PRINT("L1");
for(int ebp = 0; ebp < esi; ebp++){
PRINT("L2");
}
}
}
这是我的汇编代码:
SECTION .data ; Section containing initialized data
helloWorld0: dw "L1",10,0
helloWorld1: dw "L2",10,0
helloWorld2: dw "L3",10,0
SECTION .bss ; Section containing uninitialized data
SECTION .text ; Section containing code
extern printf ; Print function from glibc
global main ; Linker needs this to find the entry point
main:
nop ; This no-op keeps gdb happy
push ebp ; Set up stack frame for debugger
mov ebp,esp
push ebx ; Must preserve EBP, EBX, ESI & EDI
push esi
push edi
; Everything before this is boilerplate; use it for all apps
mov ebx, 3 ;L1
mov esi, 2 ;L2
mov ebp, 0 ;L3
L1:
push helloWorld0
call printf
L2:
push helloWorld1
call printf
L3:
push helloWorld2
call printf
inc ebp
cmp ebp, esi
jne L3
inc esi
cmp esi, ebx
jne L2
mov esi, 2
inc ebx
cmp ebx, 10
jne L1
; Everything after this is boilerplate; use it for all apps
pop edi ; Restore saved registers
pop esi
pop ebx
mov esp,ebp ; Destroy stack frame before returning
pop ebp
ret ; Return control to Linux
似乎代码永远不会确定ebp = esi的时间。我是汇编语言的新手,所以我的教授提供了样板。我使用了EBP,ESI和EBX,因为它们被保留下来使用。关于什么导致第三个嵌套循环无限循环的任何想法?
答案 0 :(得分:2)
在你的C中,int ebp = 0
位于两个外循环中,并在每个时间进入内循环之前运行。这不在你的asm中。
另外,不要在功能中修改EBP。你的教授的样板制作一个&#34;堆栈框架&#34; (google it),使用EBP作为帧指针。在函数结束时,mov esp,ebp
用于清理。 (好的,因为你的代码推动了printf的args但是在printf返回后没有调整ESP!)
可能未来的讲座将讨论使用[ebp + 8]
或[ebp - 4]
或其他方式访问函数args和locals。现在,只要知道这个框架指针的废话浪费了另一个宝贵的寄存器,所以你无法使用它。 (即,您可以使用的8 x86整数寄存器中只有3个寄存器,并且未被函数调用修改为EDI,ESI和EBX。)
re:Cedric关于分支条件的观点:
你的循环很好,除非我错过了什么。
你的循环都具有方便的属性,它们应该总是运行一次,因此你可以将它们写成do{}while()
循环,而无需在顶部进行额外的检查。这意味着它们可以在asm中很好地实现,底部的检查就像你一样。
因此,例如,printf(即循环体)应该在第一个内循环上运行两次:一次使用EBP = 0,一次使用EBP = 1。之后,增量将使EBP = 2,因此CMP / JNE将失效,因为EBP == ESI == 2.
对于外部循环,逻辑是相同的。整个内部循环是&#34;循环体&#34;,它在递增计数器之前运行。所以你很好。
您可以等效地使用CMP / JL进行签名比较,并在计数器小于限制时重新运行循环体。那将与C匹配。它也会改变故障模式。 2 ^ 32次穿过内环(直到inc ebp
缠绕并达到2)。对于JL,如果循环计数器太高以至于我们不应该首先进入循环,那么当前错误的失败模式将只通过内循环一次。
通常在asm中,它更容易倒数到零,例如dec ebp / jnz
不需要CMP。转换循环来做到这一点并非易事,因为外部循环计数器充当内部循环的上限。但是应该可以。你没有打印出循环中的计数器值,所以它实际上并不重要,只是循环行程计数。