我是程序员的新手,我正试图在x86中绕过函数调用。我提供了以下代码:
read_integer:
push ebp
mov ebp, esp
sub esp, 8
mov dword [ebp-4], '0'
mov dword [ebp-8], 0
push ebx
push ecx
push edx
.read_loop:
mov eax, 10
mul dword [ebp-8]
add eax, [ebp-4]
sub eax, '0'
mov [ebp-8], eax
mov eax, 3
mov ebx, 0
lea ecx, [ebp-4]
mov edx, 1
int 0x80
cmp dword [ebp-4], 10
jne .read_loop
ret
我可以使用read_integer
调用call read_integer
函数。但是,当我尝试使用.read_loop
为call .read_loop
执行相同操作时,我收到错误:
.read_loop未定义。
我做错了什么?
答案 0 :(得分:1)
.read_loop
中的点表示标签为 local 。
只能在同一范围内看到#34;由2个全球标签组成。
global_label_1:
code
.local_label
code
jne .local_label <=== no ambiguity, the label is locally defined, jumps to the label above
global_label_2:
code
.local_label <=== same name but different scope
code
它非常有用,因为代码可以在不同的过程中多次复制/粘贴,而不会出现命名冲突。
在您的情况下,删除前导点将解决它:您希望它是全局的。
read_loop:
mov eax, 10
...
call read_loop
编辑:一些汇编程序也允许访问内部标签:call read_integer.read_loop
答案 1 :(得分:1)
.read_loop
并非call
。它是标记循环开始的read_integer
的本地标签。
如果你看一下read_integer
的结尾,你会看到:
cmp dword [ebp-4], 10
jne .read_loop
只要.read_loop
不等于10,它就会跳回[ebp-4]
。这与你在C中写下以下内容类似:
do {
// Whatever
} while (*(ebp-4) != 10);
为了能够跳转某个地方你需要指定 来跳转。对位置进行硬编码会非常不方便,因此您使用标签并让汇编程序找出该标签对应的地址。
但您可能只希望某些标签在特定范围内可见(例如在read_integer
内)。也许你希望能够在其他一些函数中使用相同的标签名称,或者你只是想让那些正在阅读代码的人明白该标签是函数的本地标签。因此,一些汇编程序提供了使标签本地化的语法,如@ Jean-FrançoisFabre所述。
有些汇编程序更进一步,允许使用“匿名”标签,例如:
1:
jmp 2f ; f for forwards
; Whatever
jmp 1b ; b for backwards
2:
或者:
-:
jp + ; this is Z80 assembly, so jp isn't a typo
; Whatever
jp -
+: