Reputation: 23
I want to 'print' the argument in command line, for example, When i type "$./sum3 10" (at command line), number '10' must be shown next line
(like this)
$./sum3 10
10
and this is the code.
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
I expected the stack will be
--------------------------stack top
10 (argv[1], [p_argv+4])
./sum3 (argv[0], [p_argv])
...
pointer to argv (EBP+12)
number of arguments (EBP+8)
return address of main
EBP
----------------------- stack bottom
But,
the result is
$./sum3 10
0
I cannot understand why '0' is shown. so how can i get the right number(argument)?
Upvotes: 2
Views: 9558
Reputation: 14399
The example looks like an "assembly-coded" C-function, e.g. a C compiler adds some startcode and calls it like a function. In this startcode the Linux commandline is processed to C parameters which looks like
int main(int argc, char *argv[]) resp. int main(int argc, char **argv)
You get only two arguments on the stack: a number (argc) and a pointer to a list of pointers to a string. You have to dereference these pointers.
Take a look at this example:
; 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
A pure assembly program which is called by the shell gets the arguments slightly different on the stack. There's an excellent article about it: NASM - Linux Getting command line parameters. Try my example:
; 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)
Upvotes: 4