I'm writing a code that prints out the 2nd argument of a program. I understand that ebp+8
holds number of argument, ebp+12
holds address of name of program and so on. So far I have:
%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
The executable is called lynarr. When I execute lynarr abcd
, I'm able to print the program name (ie lynarr) but I don't understand how to print the 2nd argument. I'm using redhat-linux and nasm 2.10.07. Any ideas?
dword [ebp+12]
is a pointer to an array of string pointers. The first element of that array is a pointer to the first string, the second element is a pointer to the second string etc. Each pointer is 32-bits (4 bytes) wide.
To get a pointer to the second string would require getting the pointer at dword [ebp+12] + 4
. You can't do that directly in x86 addressing. You can do it by moving dword [ebp+12]
into a register like EAX, add 4 to it (since a pointer is 4 bytes wide) and then dereference that to get a pointer of the second string.
Replace:
mov eax, dword [ebp+16] ; prints 1st letter of 2nd argument
mov al, byte[eax]
call print_string
With:
mov eax, dword [ebp+12]
mov eax, [eax+4] ; EAX = pointer to 2nd argument
call print_string
This would print out the second argument. The first argument can be printed out with:
mov eax, dword [ebp+12]
mov eax, [eax] ; EAX = pointer to 1st argument
call print_string
Of course mov eax, [eax+8]
would get the 3rd argument and so on.
You can't use print_string
to print a single character in a register (like AL). EAX must be a pointer to a NUL(\0) terminated string.
Something else you can do is use scaled index addressing to step through an array (like your arguments):
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
With this idea you can probably see how you can create a loop that goes through the arguments. I leave that as an exercise for the reader. This is another handy quick reference for addressing modes.