我想在命令行中“打印”参数, 例如, 当我在命令行输入“ $。/ sum3 10”时, 数字'10'必须在下一行显示
(像这样)
$。/ sum3 10
10
这是代码。
segment .bss
p_arv resd 1
segment .text
global main
main:
enter 0,0
pusha
mov eax, dword [ebp+12] ; move pointer to argv to eax
mov [p_argv], eax
mov eax, [p_argv + 4] ; move number '10' to eax
call print_int
call print_nl
popa
mov eax, 0
leave
ret
我希望堆栈会
--------------------------堆栈顶部
10(argv [1],[p_argv + 4])
./sum3(argv [0],[p_argv])
...
指向argv的指针(EBP + 12)
参数数量(EBP + 8)
main的返回地址
EBP
-----------------------堆栈底部
但是
结果是
$。/ sum3 10
0
我不明白为什么显示“ 0”。 那么我如何获得正确的数字(参数)?
答案 0 :(得分:0)
该示例看起来像一个“汇编代码” C函数,例如C编译器会添加一些开始代码,并像函数一样对其进行调用。在此起始代码中,Linux命令行被处理为C参数,看起来像
int main(int argc, char *argv[]) resp. int main(int argc, char **argv)
在堆栈上仅得到两个参数:一个数字(argc)和一个指向字符串的指针列表的指针。您必须取消引用这些指针。
看看这个例子:
; Name: get_argv_gcc.asm
; Assemble: nasm -felf32 get_argv_gcc.asm
; Link: gcc -m32 -oget_argv_gcc get_argv_gcc.o
; Run: ./get_argv_gcc arg1 arg2 arg3
SECTION .data
argcstr db `argc = %d\n\0` ; backquotes for C-escapes
argvstr db `argv[%u] = %s\n\0`
SECTION .text
global main
extern printf
main:
push ebp ; Prolog
mov ebp, esp
push ebx ; Callee saved registers
push esi
mov eax, [ebp + 8] ; argc
push eax
push argcstr
call printf ; Call libc
add esp, (2*4) ; Adjust stack by 2 arguments
mov esi, [ebp + 12] ; **argv
mov ebx, 0 ; Index of argv
.J1:
mov eax, [esi + ebx * 4] ; *argv[ebx]
test eax, eax ; Null pointer?
je .J2 ; Yes -> end of loop
push eax ; Pointer to string
push ebx ; Integer
push argvstr ; Pointer to format string
call printf ; Call libc
add esp, (3*4) ; Adjust stack by 3 arguments
inc ebx
jmp .J1 ; Loop
.J2:
xor eax, eax ; Returncode = return(0)
pop esi ; Epilog
pop ebx
leave
ret
shell调用的纯汇编程序在堆栈上获取的参数略有不同。有一篇很棒的文章:NASM - Linux Getting command line parameters。试试我的例子:
; Name: get_argv.asm
; Assemble: nasm -felf32 get_argv.asm
; Link: ld -m elf_i386 -o get_argv get_argv.o
; Run: ./get_argv arg1 arg2 arg3
SECTION .data
LineFeed dw 10
nullstr db '(null)',0
argcstr db 'argc = '
argcstr1 db '---------------',0
argvstr db 'argv['
argvstr1 db '---------------',0
argvstr2 db '] = ',0
SECTION .text
global _start
_start:
push ebp
mov ebp, esp
mov eax, [ebp + 4] ; argc
mov edi, argcstr1
call EAX_to_DEC ; Convert EAX to a string pointed by EDI
mov esi, argcstr
call PrintString
mov esi, LineFeed
call PrintString
xor ecx, ecx
.J1:
mov eax, ecx
mov edi, argvstr1
call EAX_to_DEC ; Convert EAX to a string pointed by EDI
mov esi, argvstr
call PrintString
mov esi, argvstr2
call PrintString
mov esi, [ebp+8+4*ecx] ; argv[ECX]
call PrintString
test esi, esi
jz .J2
mov esi, LineFeed
call PrintString
add ecx, 1
jmp .J1
.J2:
.exit:
mov esi, LineFeed
call PrintString
mov esp, ebp
pop ebp
mov eax, 1 ; SYS_EXIT
xor ebx, ebx ; Exit code = 0 = no error
int 0x80 ; Call Linux
PrintString: ; ARG: ESI Pointer to ASCIZ string
pusha
test esi, esi
jne .J0
mov esi, nullstr
.J0:
mov eax, 4 ; SYS_WRITE
mov ebx, 1 ; STDOUT
mov ecx, esi
xor edx, edx ; Count of bytes to send
.J1:
cmp byte [esi], 0 ; Look for the terminating null
je .J2
add edx, 1
add esi, 1
jmp .J1
.J2:
int 0x80 ; Call Linux
popa
ret
EAX_to_DEC: ; ARG: EAX integer, EDI pointer to string buffer
push ebx
push ecx
push edx
mov ebx, 10 ; Divisor = 10
xor ecx, ecx ; ECX=0 (digit counter)
.J1: ; First Loop: store the remainders
xor edx, edx ; Don't forget it!
div ebx ; EDX:EAX / EBX = EAX remainder EDX
push dx ; Push the digit in DL (LIFO)
add cl, 1 ; = inc cl (digit counter)
or eax, eax ; AX == 0?
jnz .J1 ; No: once more
mov ebx, ecx ; Store count of digits
.J2: ; Second loop: load the remainders in reversed order
pop ax ; get back pushed digits
or al, 00110000b ; to ASCII
mov [edi], al ; Store AL to [EDI] (EDI is a pointer to a buffer)
add edi, 1 ; = inc edi
loop .J2 ; until there are no digits left
mov byte [edi], 0 ; ASCIIZ terminator (0)
mov eax, ebx ; Restore Count of digits
pop edx
pop ecx
pop ebx
ret ; RET: EAX length of string (w/o last null)