When you start your program from a terminal, Linux gives you TONS of information on the stack that you can use even if you don't pass any parameters to your program.
This is what the stack looks like when you start your program:

Argument Count
This will ALWAYS be at least 1, even without passing any parameters to your program. Why? Linux will always give you the path to your app.
My code for this tut is in ~/asm/projects/reverse so when I run reverse, the path will be: ./reverse.
gunner@LinuxDevel ~/asm/projects/reverse $ ./reverse hello ./reverse
Lets go back to the asm directory and run from there:
gunner@LinuxDevel ~/asm/projects/reverse $ cd ../../ gunner@LinuxDevel ~/asm $ ./projects/reverse/reverse hello ./projects/reverse/reverse
Don't mind the hello arg, since the code exits if there are no args, I just used that so it will be satisfied.
Aguments Block
After the pointer to the path comes pointers to each passed argument, followed by a NULL pointer. This marks the end of passed arguments.
Environment Block
After the arguments and NULL pointer, Linux will give us pointers to MANY Environment Variables followed again by a NULL pointer to mark the end of the variables. This list can contain well up to 200 items depending on your system.
Command line parameters can be used as input to your program or as switches to tell your program what to do. We will learn how to parse the parameters and for fun, reverse them "in place" and display them.
MAXARGS equ 5 ; 1 = program path 2 = 1st arg 3 = 2nd arg etc...
sys_exit equ 1
sys_read equ 3
sys_write equ 4
stdin equ 0
stdout equ 1
stderr equ 3
SECTION .data
;szErrMsg db "Too many arguments. The max number of args is 4", 10
;ERRLEN equ $-szErrMsg
szLineFeed db 10
SECTION .text
global _start
_start:
nop
push ebp
mov ebp, esp
cmp dword [ebp + 4], 1
je NoArgs ; no args entered
; uncomment the following 2 lines to limit args entered
; and set MAXARGS to Total args wanted + 1
; cmp dword [ebp + 4], MAXARGS ; check total args entered
; ja TooManyArgs ; if total is greater than MAXARGS, show error and quit
mov ebx, 3
DoNextArg:
mov edi, dword [ebp + 4 * ebx]
test edi, edi
jz Exit
call GetStrlen
push edx ; save string length for reverse
mov ecx, dword [ebp + 4 * ebx]
call DisplayNorm ; display arg text normally
pop edi ; move string length into edi
mov esi, dword [ebp + 4 * ebx]
call ReverseIt ; now display in reverse
inc ebx ; step arg array index
jmp DoNextArg
ReverseIt:
push ebx
add esi, edi
Next:
mov eax, sys_write
mov ebx, stdout
mov ecx, esi
mov edx, 1
int 80H
dec esi
dec edi
jns Next
mov ecx, szLineFeed
mov edx, 1
mov eax, sys_write
mov ebx, stdout
int 80H
pop ebx
ret
NoArgs:
; No args entered,
; start program without args here
jmp Exit
DisplayNorm:
push ebx
mov eax, sys_write
mov ebx, stdout
int 80H
pop ebx
ret
GetStrlen:
push ebx
xor ecx, ecx
not ecx
xor eax, eax
cld
repne scasb
mov byte [edi - 1], 10
not ecx
pop ebx
lea edx, [ecx - 1]
ret
; TooManyArgs:
; mov eax, sys_write
; mov ebx, stdout
; mov ecx, szErrMsg
; mov edx, ERRLEN
; int 80H
Exit:
mov esp, ebp
pop ebp
mov eax, sys_exit
xor ebx, ebx
int 80H
When run this will be the output:

Ok, lets go though the code:
MAXARGS equ 5 ; 1 = program path 2 = 1st arg 3 = 2nd arg etc... sys_exit equ 1 sys_read equ 3 sys_write equ 4 stdin equ 0 stdout equ 1 stderr equ 3
I don't like using hard coded numbers (or others that do), it just makes the code less readable. So I define some equates to use instead.
push ebp
mov ebp, esp
cmp dword [ebp + 4], 1
je NoArgs ; no args entered
; uncomment the following 2 lines to limit args entered
; and set MAXARGS to Total args wanted + 1
; cmp dword [ebp + 4], MAXARGS ; check total args entered
; ja TooManyArgs ; if total is greater than MAXARGS, show error and quit
We will save esp and use ebp as our base pointer to the stack. So now, instead of the arg count being at [esp], it is now at [ebp + 4]
We check to see if this value is 1 (No args entered) if it is, we start the program anyway you want. This code I just exit.
Next we can check to see if there are too many arguments entered and display a message if wanted. Uncomment the relevant code to see it work.
Now lets loop through the arg pointers:
mov ebx, 3
DoNextArg:
mov edi, dword [ebp + 4 * ebx]
test edi, edi
jz Exit
call GetStrlen
push edx ; save string length for reverse
mov ecx, dword [ebp + 4 * ebx]
call DisplayNorm ; display arg text normally
pop edi ; move string length into edi
mov esi, dword [ebp + 4 * ebx]
call ReverseIt ; now display in reverse
inc ebx ; step arg array index
jmp DoNextArg
Here we will use ebx as the index into the argument array. Why start at 3? Since we pushed ebp, the args now start at [ebp + 12], 4 * 3 = 12, so we just increment ebx to get the next array pointer.
First thing we do is check to see if we have a NULL pointer, and if we do we are at the end of the argument array.
Have a valid pointer? Good, now we will get the length of the string, display it normally and display it reversed. Increment ebx for the next array element and loop back to the beginning and get next arg (if there is one). Instead of displaying and reversing the arg text, this is where you would check for switches that tell your program what to do.
GetStrlen:
push ebx
xor ecx, ecx
not ecx
xor eax, eax
cld
repne scasb
mov byte [edi - 1], 10
not ecx
pop ebx
lea edx, [ecx - 1]
ret
Here we will use scasb to scan the string for a NULL terminator. We could use scasb in a loop of our own, but we will let the CPU do the loop with repne (repeat while not equal)
scasb looks for the byte that is in eax, we want to find a NULL (0) so we zero out eax. ecx will contain -1 (4,294,967,295), and edi is a pointer to the string to search.
scasb will scan a byte in the string, and if the one we are looking for is not found, it will increment the pointer in edi and decrement ecx and keep repeating until it finds our character. It exits its loop when the character is found, or when ecx equals 0. Once 0 is found, we replace it with the linefeed character (10), and move the string length into edx.
That is about as simple as it gets. Here is a little assignment for you:
Taking the code above, and from what I explained; modify the code to show all the system variables INSTEAD of any command line params.
Attached File(s)
-
reverse.tar.gz (1.92K)
Number of downloads: 104







MultiQuote






|