You are not logged in.

#1 2009-03-03 13:40:27

Aprz
Member
From: Newark
Registered: 2008-05-28
Posts: 277

[SOLVED]GAS x86 assembly trouble retrieving argc

Blah, this has been bugging me. I've been trying to get argc to print, but haven't successfully done it.

I am using Binutils 2.19.1.20090205.

[andrew@archlinux ~]$ cat test.s
.globl _start

_start:
        movl    $4, %eax        # write system call
        movl    $1, %ebx        # STDOUT
        movl    0(%esp), %ecx   # argc
        movl    $1, %edx        # allocate one space
        int     $0x80           # interrupt

        movl    $1, %eax        # exit system call
        movl    $0, %ebx        # return 0
        int     $0x80           # interrupt
[andrew@archlinux ~]$ ./test 1 2 3 4 5
[andrew@archlinux ~]$

I can get the program name and argv[], but I just cannot get argc. I've also looked at some other tutorials and they do it by using pop (popl in AT&T syntax), but I am guessing that is only for NASM (or anything that uses Intel's syntax, I am not sure) since I haven't been do it. hmm

By the way, I am reading Programming from the Ground Up. It really got me when I read about retrieving argc on page 64 (page 70 on the pdf) because it said

So, what files are we opening? In this example, we will be opening the file specified on the command line. Fortunately, command-line parameters are already stored by Linux in an easy-to-access location, and already null-terminated. When a Linux program begins, all pointers to command-line arguments are stored on the stack. The number of arguments is stored at 8(%esp), the name of the program is stored at 12(%esp), and the arguments are stored from 16(%esp) on. In the C programming language , this is referred to as the argv array, so we will refer to it that way in our program.

Notice that the book says argc is 8(%esp). When I did this, it returned the value of argv[1], which, when I browsed Google, found it to be pretty consistent that 8(%esp) is argv[1]. I found that 0(%esp) is suppose to be argc so maybe it's just a mistake in the book, but I am not really positive. I also saw in the source code in the book that the author used 0(%esp) for argc, however, he did not actually use it in that way. He just had it prepped for that (look at page 58 of the book or page 64 on the pdf).

# STACK POSITIONS
 .equ ST_SIZE_RESERVED, 8
 .equ ST_FD_IN, -4
 .equ ST_FD_OUT, -8
 .equ ST_ARGC, 0       #Number of arguments
 .equ ST_ARGV_0, 4    #Name of program
 .equ ST_ARGV_1, 8    #Input file name
 .equ ST_ARGV_2, 12    #Output fle name

Blah, that really threw me off.

I was thinking maybe I wasn't allocating enough space in %edx so I tried different sizes also, but the results were the same.

Anyhow, this argc issue is the only issue I am having and I would like to know what I can do to retrieve argc so I wont feel so incomplete.

Many thanks in advance.

Edit: Ah, I could get it to work this way.

[andrew@archlinux ~]$ .globl _start

_start:
        movl    $1, %eax
        movl    0(%esp), %ebx
        int     $0x80
[andrew@archlinux ~]$ ./test 1 2 3
[andrew@archlinux ~]$ echo $?
4
[andrew@archlinux ~]$ ./test 1
2

and so on, you get the idea. So my problem must be with trying to print out numbers.

Edit: Me and a friend were talking about it and we determined it's because I need to convert argc into a character or string, which for single digits would be simply to add 48 I believe. To convert multidigit numbers, I created an aglorithm in Perl way back when I decided to challenge myself by not using modulus or chop() or regular expression or anything really fancy.

for(my $index = 0; $index <  @digits; $index++) {
   if($digits[$index] == -1) {
      $index++;
                $track[0]--;
        }
        for(my $num = 1; $num <= 10; $num++) {
           $div = ($input - $total)/($num * (10 ** (@digits - $index - $track[0] - $digits[$index] - 1)));
                if($div == 1) {
                   $digits[$index] = $num;
                        $num = 100;
                }
                if($div < 1) {
                        $digits[$index] = $num - 1;
                        $num = 100;
                }
       }
       $total = $total + ($digits[$index] * (10 ** (@digits - $index - $track[0] - 1)));
}

I wrote it when I was younger and slightly inexperience so it's a bit sloppy, but it pretty much works like this.

$div = (54321 - ((0 * 10,000) + (0 * 1,000) + (0 * 100) + (0 * 10) + (0 * 1)))/(1 * (10 ** (4 - 0)));
$div = (54321 - (0 + 0 + 0 + 0 + 0))/(1 * (10 ** 4));
$div = (54321 - (0 + 0 + 0 + 0 + 0))/(1 * (10,000));
$div = (54321 - 0)/10,000;
$div = 54321/10,000;
$div = 5.4321
...
$div = 54321/(2 * 10,000);
...
$div = 54321/20,000;
$div = 2.71605;
...
$div = 54321/30,000;
$div = 1.8107;
...
$div = 54321/40,000;
$div = 1.358025;
...
$div = 54321/50,000;
$div = 1.08642;
...
$div = 54321/60,000;
$div = 0.90535;

So... that shouldn't be too much more complicated to put into play in assembly. It will just look very scary. big_smile

Well, problem solved. Something so simple, yet I turned it into a complicated mission, haha and overlooked how printing things work in assembly. *feels like a fool*

Last edited by Aprz (2009-03-03 14:41:56)

Offline

Board footer

Powered by FluxBB