Author Topic: Get command-line arguments count  (Read 6085 times)

Offline alexbnc

  • Jr. Member
  • *
  • Posts: 6
Get command-line arguments count
« 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:

Code: [Select]
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

Code: [Select]
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!
« Last Edit: October 30, 2012, 02:57:37 PM by alexbnc »

Offline TightCoderEx

  • Full Member
  • **
  • Posts: 103
Re: Get command-line arguments count
« Reply #1 on: October 30, 2012, 03:36:36 PM »
cmp     [ebx], 2

Your example tests the value of ebx, not what it's pointing to.

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Get command-line arguments count
« Reply #2 on: October 30, 2012, 10:32:57 PM »
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.

Offline TightCoderEx

  • Full Member
  • **
  • Posts: 103
Re: Get command-line arguments count
« Reply #3 on: November 01, 2012, 12:16:10 AM »
I should have paid attention, win32. Example would have worked using linux. Mine is in error in either case.

Offline Frank Kotler

  • NASM Developer
  • Hero Member
  • *****
  • Posts: 2356
  • Country: us
Re: Get command-line arguments count
« Reply #4 on: November 01, 2012, 01:06:22 AM »
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


Offline alexbnc

  • Jr. Member
  • *
  • Posts: 6
Re: Get command-line arguments count
« Reply #5 on: November 01, 2012, 11:53:16 AM »
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:
Code: [Select]
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:
Code: [Select]
nasm -f win32 test.asm -o test.oThe .exe is created with this command:
Code: [Select]
gcc -nostartfiles -s -Os test.o -o test.exeI test it by simply typing
Code: [Select]
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.
« Last Edit: November 01, 2012, 11:54:55 AM by alexbnc »

Offline Keith Kanios

  • Full Member
  • **
  • Posts: 383
  • Country: us
    • Personal Homepage
Re: Get command-line arguments count
« Reply #6 on: November 01, 2012, 02:14:45 PM »
Code: [Select]
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.

Offline alexbnc

  • Jr. Member
  • *
  • Posts: 6
Re: Get command-line arguments count
« Reply #7 on: November 01, 2012, 03:38:04 PM »
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!