Mnkisd
Mnkisd

Reputation: 512

How to access the command line arguments (./program arg1 arg2 arg3)

How could I access to those arguments? I have read that they are stored in r1, but I am not able to access them.

For example, in this code:

.global main

main:
        ldr     r2, [r1, #4]
        ldr     r0, [r2]
        bx      lr

If I execute the program with 7 value:

./program 7
echo $?

I got 55, that is the decimal ASCII representation of 7.

So I tried to add SUB line:

.global main

main:
        ldr     r2, [r1, #4]
        sub     r2,r2,#48        // to actually obtain 7
        ldr     r0, [r2]
        bx      lr

But I got 0. Why?

EDIT (it works):

.global main

main:
        ldr     r2, [r1,#4]
        ldr     r0, [r2]
        sub     r0, r0, #48
        bx      lr

But what I have not clear is, why doesn't it work if I use r0 instead of r2? Like this:

.global main

main:
        ldr     r0, [r1,#4]
        sub     r0, r0, #48
        bx      lr

Upvotes: 0

Views: 306

Answers (2)

old_timer
old_timer

Reputation: 71516

#include <stdio.h>
int main ( int argc, char *argv[] )
{
    printf("%d\n",argv);
    return(0);
}
so.c: In function ‘main’:
so.c:5:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘char **’ [-Wformat=]

that is your first problem

#include <stdio.h>
int main ( int argc, char *argv[] )
{
    printf("%d\n",argv[1][0]);
    return(0);
}
./so 7
55

55 = 0x37

If you had gotten past that this would be your second problem

Could solve the first by simply asking the compiler to show you a path.

#include <stdio.h>
int main ( int argc, char *argv[] )
{
    return(argv[1][0]);
}

   0:   e5913004    ldr r3, [r1, #4]
   4:   e5d30000    ldrb    r0, [r3]
   8:   e12fff1e    bx  lr

Think about how the C function is called and then translate that to assembly. An array of pointers to strings.

And then depending on the instruction set you may have additional issues in the factorial function.

EDIT:

.global main

main:
        ldr     r2, [r1, #4]   <--- address of the pointer to the string
        sub     r2,r2,#48  <---- hoses the pointer to the string
        ldr     r0, [r2] <---- who knows what this is reading
        bx      lr

Look at the code the compiler generated (assuming 7 is the first parameter on the command line ./so 7)

   0:   e5913004    ldr r3, [r1, #4] <---- pointer to string (param 1)
   4:   e5d30000    ldrb    r0, [r3] <---- get first byte in string
                             r0 now contains 0x37
                    ldrb    r0, [r3,#1] <----- If I added this line
                             r0 now contains 0x00 string termination
   8:   e12fff1e    bx  lr   

Now think about Frant's answer, how you convert a string to a number if the string is some number in some base ("7", "0x123", "68", etc).

Upvotes: 2

Frant
Frant

Reputation: 5895

You are passing the string "7" as an argument, not the value 7, you have to convert it into a binary value.

Remember, the signature for the main function is int main(int argc, char** argv, char** envp).

That is, the number of argument will be in r0, the pointer to the array of the parameters strings will be in r1, and the pointer to the array of environment zero-terminated strings will be in r2.

In order to retrieve "7", you need to access argv1 - argv[0] will be the zero-terminated string containing path to the program you are executing.

If you are passing 1 to 9, you can just substract '0' or 0x30 in order to the value retrieved in argv1.

For other values than '1'.. '9', you should call atoi() from your assembly program, or convert it by yourself for the fun.

Procedure Call Standard for the ARM Architecture is a good read for understanding how to call C functions form assembly or vice versa.

Upvotes: 1

Related Questions