NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: alexbnc on October 30, 2012, 02:55:29 PM
-
Hi, everybody
I'm new to assembly and, as I'm trying to understand memory handling with push and pop, I started to create a little win32 console application that should get the command line arguments count (argc), check if they are more than 2 and show an error message if not so. That simple. The code in C/C++ would be:
void ShowError() {
printf ("Command unrecognized!");
}
int main (int argc. char** argv[]) {
if (argc<2) ShowError();
return 0;
}
Now, in Assembly (with NASM), this is what I have
global Start
extern _printf
extern _ExitProcess@4
section .data
ArgumentsError db 'Not enough arguments %d!', 10, 0
section .text
Start:
; Get argc (which I don't know if really works)
pop ebx
; If argc < 2 then show error
cmp ebx, 2
jl ShowError
; Close application with no error
push 0
call _ExitProcess@4
hlt
ShowError:
sub esp, 4
push ArgumentsError
call _printf
add esp, 4
ret
So, if I compile this file with NASM and link it with GCC into a test.exe win32 binary and execute it (without any argument in the command line), I don't get the error. It's like the cmp instruction's result is always greater than 2. I don't know what am I doing wrong. If I use jg instead of jl I get that error message.
Thanks for your help!
-
cmp [ebx], 2
Your example tests the value of ebx, not what it's pointing to.
-
cmp [ebx], 2
Your example tests the value of ebx, not what it's pointing to.
Not that simple.
First, he pops (what he thinks is) ARGC from the stack into ebx, and tests that value. If that was ARGC, his approach is correct as ARGC is a value, not a pointer like ARGV.
His approach does deviate from the typical "cmp DWORD[ebp+X],N" style as commonly produced by compilers, so that might have thrown you off.
However, while it seems that both of you account for the correct CDECL parameter order, you haven't accounted for the implicit return address (EIP) pushed onto the stack by the C runtime initialization.
Try mov ebx,DWORD[esp+4] instead of pop ebx, and let us know what that does.
Also, replace hlt with ret as a more appropriate failsafe.
As for the ShowError subroutine, re-think about how you are affecting the stack.
-
I should have paid attention, win32. Example would have worked using linux. Mine is in error in either case.
-
If the entrypoint had been named "_main" ("main" for Linux), I'd expect a "C style stack" - Windows, Linux, or whatever. Dunno what gcc will make of "Start". What's your command line look like?
Best,
Frank
-
Hi, everybody! Thanks for your help. I'm still not getting the desired results, but I won't give up. My code looks like this now:
global _main ; O.K. I'm on Windows, I should use this
extern _printf
extern _ExitProcess@4
section .data
ArgumentsError db 'Not enough arguments!', 10, 0
section .text
Start:
; Get argc (which I don't know if really works)
mov ebx, DWORD[esp+4] ;O.K. Let's hope argc is at that direction
; If argc < 2 then show error
cmp ebx, 2
jl ShowError
; Close application with no error
push 0
call _ExitProcess@4
ret ; Changed this too
ShowError:
sub esp, 4
push ArgumentsError
call _printf
add esp, 4
ret
I create the .obj file with this command: nasm -f win32 test.asm -o test.o
The .exe is created with this command: gcc -nostartfiles -s -Os test.o -o test.exe
I test it by simply typing test
and pressing ENTER. I should get an error telling me that there are not enough arguments in the command line. Of course, I added test to the user environment variables list.
Again, thanks for your help.
-
gcc -nostartfiles -s -Os test.o -o test.exe
There's your disconnect: -nostartfiles skips the C runtime (CRT) startup. Therefore, there is nothing to supply ARGC & ARGV as arguments (on the stack) to your entrypoint. Supplying those arguments is exactly one of the things that the CRT startup does.
Either remove -nostartfiles or utilize GetCommandLine(). Please note that GetCommandLine() is Windows (Win32 API) specific, where-as the CRT startup is rather cross-platform and thus more standard.
-
Thanks, Keith Kanios
You enlightened me. I will use _GetCommandLine. I prefer the applications to be environment independent, rather than OS independent.
I'll post the right script once I see it working. Thanks!