我正在编写代码,打印出程序的第二个参数。我了解ebp+8
持有参数的数量,ebp+12
持有程序名称的地址等等。到目前为止,我有:
%include "asm_io.inc" SECTION .data err1: db "Incorrect number of command line arguments",10,0 SECTION .text global asm_main asm_main: enter 0,0 pusha mov eax, dword [ebp+8] cmp eax, dword 2 jne ERR1 mov eax, dword [ebp+16] ; prints 1st letter of 2nd argument mov al, byte[eax] call print_string jmp asm_main_end ERR1: mov eax, err1 call print_string jmp asm_main_end asm_main_end: call print_nl popa ; restore all registers leave ret
该可执行文件称为lynarr。当我执行时lynarr abcd
,我可以打印程序名称(即lynarr),但是我不知道如何打印第二个参数。我正在使用redhat-linux和nasm 2.10.07。有任何想法吗?
dword [ebp+12]
是指向字符串指针数组的指针。该数组的第一个元素是指向第一个字符串的指针,第二个元素是指向第二个字符串的指针,等等。每个指针的宽度为32位(4字节)。
要获得指向第二个字符串的指针,需要将指针指向dword [ebp+12] + 4
。您不能直接在x86寻址中执行此操作。您可以通过移至dword [ebp+12]
类似EAX的寄存器中,向其添加4(因为指针为4个字节宽),然后对其进行取消引用以获得第二个字符串的指针来完成此操作。
更换:
mov eax, dword [ebp+16] ; prints 1st letter of 2nd argument mov al, byte[eax] call print_string
带有:
mov eax, dword [ebp+12] mov eax, [eax+4] ; EAX = pointer to 2nd argument call print_string
这将打印出第二个参数。第一个参数可以用以下命令打印出来:
mov eax, dword [ebp+12] mov eax, [eax] ; EAX = pointer to 1st argument call print_string
当然mov eax, [eax+8]
会得到第三个参数,依此类推。
您不能使用print_string
在寄存器(如AL)中打印单个字符。EAX必须是指向以NUL(\ 0)结尾的字符串的指针。
您可以做的其他事情是使用缩放索引寻址来遍历数组(例如您的参数):
mov ebx, dword [ebp+12] xor esi, esi ; Index of first argument (index=0) mov eax, [ebx+esi*4] ; EAX = pointer to 1st argument call print_string inc esi ; Next argument (index=1) mov eax, [ebx+esi*4] ; EAX = pointer to 2nd argument call print_string inc esi ; Next argument (index=2) mov eax, [ebx+esi*4] ; EAX = pointer to 3rd argument call print_string
有了这个想法,您可能会看到如何创建一个遍历参数的循环。我把它留给读者作为练习。这是寻址模式的又一便捷参考。