I just wrote this code, it assembles fine. I used GAS and its x86_64.
I linked it like this:

ld -o ./maximum /usr/lib64/crt1.o /usr/lib64/crti.o ./maximum.o -lc

There's no errors. But then I run it and I get this:

bash: ./maximum: No such file or directory

Just to make sure, I ran it and gdb and got the same error.

Here's the code:


# PURPOSE:      This program finds the maximum number of a
#              set of data items.
#


.section .data

hello_msg:

        .asciz "Hello from GAS :)\\n"

current_data_item_msg:

        .asciz "Current data item #%d: %d\\n"

greatest_data_item:

        .asciz "Greatest data item: %d\\n"

exit_msg:

        .asciz "See ya!!\\n"

debug_1:

        .asciz "Args #: %d\\n"

debug_2:

        .asciz "Mem for args: %d + 8 bytes\\n"

.section .text

.globl main

main:

leaq (%rsp), %rdx                      # need old stack frame to get args

pushq %rbp                              # Create a new stack frame
movq %rsp, %rbp                        # following C runtime rules
pushq %rsi
pushq %rdi
pushq %rbx

movq (%rdx), %rcx                      # Move argc to counter



                pushq %rdx                      # START DEBUG: Print # args
                pushq %rcx

                pushq %rcx
                pushq $debug_1
                call printf

                addq $16, %rsp

                popq %rcx
                popq %rdx                      # END DEBUG




cmpq $2, %rcx                          # if no arguments, goto no_args
jl no_args

decq %rcx
movq %rdx, %rsi
addq $8, %rsi                          # skip the program name, store start of args in rsi

movq %rcx, %rax                        # add enough memory to the stack frame
movq $8, %rbx
mulq %rbx                              # to hold all the args
movq %rax, %rbx
addq $8, %rbx                          # add extra 8 bytes for terminating data item (0)



                pushq %rdx                      # START DEBUG: Print mem needed for args on stack
                pushq %rbx
                pushq %rcx

                subq $8, %rbx

                pushq %rbx
                pushq $debug_2
                call printf

                addq $16, %rsp
                popq %rcx
                popq %rbx
                popq %rdx                      # END DEBUG



movq %rsp, %rdi                        # Make room on stack for args
subq %rbx, %rsp                        # put starting address of args in %rdi

movq $0, %rax                          # Going to store args source index in %rax

#
# Go through argv[ i ] and put every argv on the stack
#
# Or if there are no argvs, then just use random numbers
#

# rcx: decrementing counter on number of args left
# rdi: start of stack space for storing args
# rsi: start of pointers to arg strings
# rax: current arg number

arg_loop_start:

        cmpq $0, %rcx
        je arg_quit

                pushq %rcx

                movq %rax, %r9
                pushq %r9

                pushq 0(%rsi,%rax,8)
                call atoi
                addq $8, %rsp

                popq %r9

                movq %rax, 0(%rdi,%r9,8)        # put current arg in stack

                movq %r9, %rax

                popq %rcx

        incq %rax
        decq %rcx

no_args:

        movq %rsp, %rdi
        subq $40, %rsp          # Make room for 5 random data items

        pushq $0                # Seed random number gen
        call time
        addq $8, %rsp

        pushq %rax
        call srand
        addq $8, %rsp

        movq $5, %rcx          # Use 5 random data items
        movq $0, %rax

no_args_loop_start:

        cmpq $0, %rcx
        je arg_quit

        movq %rax, %r9

        pushq %r9

        call rand
        addq $1, %rax          # Make sure its not 0

        popq %r9

        movq %rax, 0(%rdi, %r9, 8)

        movq %r9, %rax

        incq %rax
        decq %rcx

arg_quit:

        movq $0, 0(%rdi, %rax, 8)      # Add the terminating zero


pushq $hello_msg
call printf
addq $8, %rsp


movq $0, %rcx          # Put 0 in the data item index
movq (%rdi), %rbx      # Put the first number in ebx as the largest item

start_data_loop:
        movq 0(%rdi, %rcx, 4), %rdx

        pushq %rcx
        pushq %rdx

        pushq %rdx
        pushq %rcx
        pushq $current_data_item_msg
        call printf

        addq $24, %rsp

        popq %rdx
        popq %rcx

        cmpq $0, %rdx
        je data_loop_quit

        cmpq %rdx, %rbx
        jle not_larger

        movq %rdx, %rbx

not_larger:
        incq %rcx

data_loop_quit:

        pushq %rdx
        pushq $greatest_data_item
        call printf

        addq $16, %rsp

        pushq $exit_msg
        call printf

        sub $8, %rsp


popq %rbx              # Destroy the stack frame and exit
popq %rdi
popq %rsi
movq %rbp, %rsp
popq %rbp

ret


Btw, I'm just starting to learn assembly so I'm guessing this code doesn't look to good :P

In fact, I'm pretty sure I used mulq wrong here:

movq %rcx, %rax                        # add enough memory to the stack frame
movq $8, %rbx
mulq %rbx 
                            # to hold all the args
movq %rax, %rbx
addq $8, %rbx                          # add extra 8 bytes for terminating data item (0)

Thanks,
mikfig
Posted on 2011-09-14 06:36:06 by mikfig
Have you tried "chmod +x ./maximum" before running the executable?
Posted on 2011-09-14 10:51:14 by LocoDelAssembly
Disclaimer: I am not familiar with 64-bit code. However... I have gotten the exact same error message when linking directly with ld in 32-bit code. The "secret" is this: ld (32-bit) asks, by default, for "/lib/ld-linux.so.1", which does not exist on my system. This is the file that's not found. The workaround is to tell ld "-I /lib/ld-linux.so.2". Problem solved.

I suspect you're encountering a similar problem. I don't know what the "correct" name for the interpreter/dynamic linker is for 64-bit code. (maybe the same?) I would suggest using gcc to do your linking - it knows where to find stuff!


gcc -o maximum maximum.o


That may add a few bytes to your executable, compared to using ld directly, but "no big deal".

I can't speak to your use of "mulq", but it looks to me as if, after manipulating %rbx, you don't subtract if from %rsp, so I don't think it's doing what you want.

Best,
Frank

Posted on 2011-09-14 11:08:44 by fbkotler

Disclaimer: I am not familiar with 64-bit code. However... I have gotten the exact same error message when linking directly with ld in 32-bit code. The "secret" is this: ld (32-bit) asks, by default, for "/lib/ld-linux.so.1", which does not exist on my system. This is the file that's not found. The workaround is to tell ld "-I /lib/ld-linux.so.2". Problem solved.

I suspect you're encountering a similar problem. I don't know what the "correct" name for the interpreter/dynamic linker is for 64-bit code. (maybe the same?) I would suggest using gcc to do your linking - it knows where to find stuff!


gcc -o maximum maximum.o


That may add a few bytes to your executable, compared to using ld directly, but "no big deal".

I can't speak to your use of "mulq", but it looks to me as if, after manipulating %rbx, you don't subtract if from %rsp, so I don't think it's doing what you want.

Best,
Frank


Ok, I linked it with gcc. Now I got a segmentation fault, but at least I can debug that. As for mulq, I did subtract %rbx from %rsp, I just didn't show it in that little code snippet.

Thanks,
mikfig
Posted on 2011-09-14 14:52:44 by mikfig
You may want to read "System V AMD64 ABI convention" because you seem to be invoking functions in a c-like fashion.

%rdi, %rsi, %rdx, %rcx, %r8, %r9, stack (+ RAX for vararg functions like printf).
+stack  must be aligned on 16 bytes.
Posted on 2011-09-15 04:21:57 by drizz

You may want to read "System V AMD64 ABI convention" because you seem to be invoking functions in a c-like fashion.

%rdi, %rsi, %rdx, %rcx, %r8, %r9, stack (+ RAX for vararg functions like printf).
+stack  must be aligned on 16 bytes.


Ok thanks, will do.
Posted on 2011-09-15 15:15:43 by mikfig
Posted on 2011-09-15 20:30:26 by p1ranha
Short piece on Linux 64-bit with sys_calls here, too...

http://callumscode.com/blog/3

Best,
Frank

Posted on 2011-09-15 22:59:32 by fbkotler

Short piece on Linux 64-bit with sys_calls here, too...

http://callumscode.com/blog/3

Best,
Frank




Alright thanks guys, I've read through some of the AMD64 ABI and figured out most of my problems through that. That's also a cool article fbkotler. Thanks :). So I updated my code, got it running for the most part. It runs just fine if you pass no arguments or if you pass less than 8 arguments. If you pass 8 or more, it will run and get to the final ret instruction; but it will exit with a segmentation fault error.
I'm not sure what the cause is, because I debugged it with gdb and the stack is cleaned up. The registers that are supposed to be reset to the value they had before the function was called isn't being completely done right for some reason. But when it runs with less than 8 arguments that is still the case, just to a lesser extent. I.e. more of the registers supposed to be saved are set to their original value when less than 8 arguments are passed, but not all of them are. Also, when I break at the last instruction, ret, and reset the values to their originals there is still a segmentation fault. So I guess I'm going to have to look more into this.

Anyways, here's the better code:

# PURPOSE:      This program finds the maximum number of a
#                      set of data items. The data items can be given as
#           command line arguments or 5 random data items will be generated.

.section .data

hello_msg:

        .asciz "Hello from GAS\n"

current_data_item_msg:

        .asciz "Current data item #%lld: %lld\n"

greatest_data_item:

        .asciz "Greatest data item: %lld\n"

exit_msg:

        .asciz "See ya!!\n"

debug_2:

        .asciz "Mem for args: %lld + 8 bytes\n"

.section .text

.globl main

main:

pushq %rbp                              # Create a new stack frame
movq  %rsp, %rbp                        # following C runtime rules
pushq %rsi
pushq %rdi
pushq %rbx
pushq %r12
pushq %r13
pushq %r14
pushq %r15


decl %edi              # program name not an "argument"
addq $8, %rsi

#
#
#      INPUTS
#
#      int argc        :      ebx
#      char** argv    :      rsi
#     
#

cmpl $1, %edi                          # if no arguments, goto no_args
jl no_args

# previous operation on %edi
# clears higher 32 bits

movq  %rdi, %rbx
imulq $8, %rbx                          # add enough memory to the stack frame
addq  $8, %rbx                          # to hold all the args
                                  # add extra 8 bytes for terminating zero


                pushq %rdi                      # START DEBUG: Print mem needed for args on stack
                pushq %rbx
                pushq %rsi

                subq $8, %rbx

                movq %rbx, %rsi
                movq $debug_2, %rdi
                movq $0, %rax
                call printf

                popq %rsi
                popq %rbx
                popq %rdi                      # END DEBUG


movq %rdi, %rcx
movq %rsp, %rdi                        # Make room on stack for args
subq %rbx, %rsp                                # put starting address of args in %rdi

movq $0, %rax                          # Going to store args source index in %rax

#
# Go through argv[ i ] and put every atoll(*argv) on the stack
#
# Or if there are no argvs, then just use random numbers
#

# rcx: decrementing counter on number of args left
# rdi: start of stack space for storing args
# rsi: start of pointers to arg strings
# rax: current arg number

arg_loop_start:

                cmpq $0, %rcx
je arg_quit

                pushq %rcx

                movq %rax, %r9

                pushq %r9
                pushq %rdi
                pushq %rsi

                movq (%rsi,%rax,8), %rdi
                call atoll                      # 64-bit version of atoi

                pop %rsi
                pop %rdi
                pop %r9

                movq %rax, (%rdi,%r9,8)        # put current arg in stack

                movq %r9, %rax

                popq %rcx

        incq %rax
        decq %rcx
        jmp arg_loop_start

no_args:

        movl $0, %edi          # Seed random number gen
        call time

        movl %eax, %edi
        call srand

        movq %rsp, %rdi
        subq $40, %rsp          # Make room for 5 random data items

        movq $5, %rcx          # Use 5 random data items
        movq $0, %rax

# rcx: decrementing counter on number of args left
# rdi: start of stack space for storing args
# rax: current arg number

no_args_loop_start:

        cmpq $0, %rcx
        je arg_quit

        movq %rax, %r9

        pushq %rdi
        pushq %rcx
        pushq %r9

        call rand
        addl $1, %eax                  # Make sure its not 0

        popq %r9
        popq %rcx
        popq %rdi

        movq %rax, (%rdi, %r9, 8)      # rand putting num in %eax should zero out top 32 bits

        movq %r9, %rax

        incq %rax
        decq %rcx
        jmp no_args_loop_start

arg_quit:

        movq $0, (%rdi, %rax, 8)        # Add the terminating zero

pushq %rdi

movq $hello_msg, %rdi
movq $0, %rax
call printf

popq %rdi

movq $0, %rcx          # Put 0 in the data item index
movq (%rdi), %rbx      # Put the first number in rbx as the largest item

start_data_loop:
        movq (%rdi, %rcx, 8), %rdx

        pushq %rbx
        pushq %rcx
        pushq %rdi
        pushq %rdx

        # 3rd argument already in rdx
        movq %rcx, %rsi
        movq $current_data_item_msg, %rdi
        movq $0, %rax
        call printf

        popq %rdx
        popq %rdi
        popq %rcx
        popq %rbx

        cmpq $0, %rdx
        je data_loop_quit

        cmpq %rdx, %rbx
        jge not_larger

        movq %rdx, %rbx

not_larger:
        incq %rcx
        jmp start_data_loop

data_loop_quit:

        incq %rcx                  # need to pop off terminating zero too
        imulq $8, %rcx
        addq %rcx, %rsp        # clean up used stack space

        movq %rbx, %rsi
        movq $greatest_data_item, %rdi
        movq $0, %rax
        call printf

        movq $exit_msg, %rdi
        movq $0, %rax
        call printf

popq %r15              # Destroy the stack frame and exit
popq %r14
popq %r13
popq %r12
popq %rbx              # AMD64 ABI, have to preserve %rbp, %rbx, %r12-%r15
popq %rdi              # Intel386 ABI, have to preserve %rbp, %rbx, %rdi, %rsi
popq %rsi
movq %rbp, %rsp
popq %rbp

ret


Oh, and I'm thinking that maybe the fact that I neglected to align my stack on 16 bytes may be causing the segfault but I'm not sure.
It is 8 byte aligned at the least. I guess I'll have to think about it. But at least I got it working in most cases.

And thanks a lot for the help guys :)
Posted on 2011-09-17 02:27:42 by mikfig
An easy way to keep stack aligned on 16 bytes is this:

function/label "main" -  you can depend on the fact that after entry stack is aligned on 8 bytes ("call" instruction makes the stack unaligned), hence you need ODD number of pushes(or subtract 8*ODD) after function entry

main:
  push rbp
;-- stack aligned

or
main:
  sub rsp,3*8
;-- stack aligned


Next, always have EVEN number of pushes(or subtract 8*EVEN) in the code
push rax
push rdx
call somefunc
pop rdx
pop rax

or

sub rsp,4*8
call somefunc
add rsp,4*8









Posted on 2011-09-17 06:48:28 by drizz
Stack alignment in x64 is critical.  As drizz correctly points out the stack must be aligned to 16 bytes.  One of the easiest things to do is to push rbp upon function entry which will realign the stack due to the call.  Follow with a mov  rbp, rsp and you can easily use RBP as the base pointer to the argument offsets ( ie: mov rax, ).  There are also optimizations you can make using the x64 ABI but we'll save that  topic for another day.
Posted on 2011-09-17 11:03:16 by p1ranha

Stack alignment in x64 is critical.  As drizz correctly points out the stack must be aligned to 16 bytes.  One of the easiest things to do is to push rbp upon function entry which will realign the stack due to the call.  Follow with a mov  rbp, rsp and you can easily use RBP as the base pointer to the argument offsets ( ie: mov rax, ).  There are also optimizations you can make using the x64 ABI but we'll save that  topic for another day.


An easy way to keep stack aligned on 16 bytes is this:

function/label "main" -  you can depend on the fact that after entry stack is aligned on 8 bytes ("call" instruction makes the stack unaligned), hence you need ODD number of pushes(or subtract 8*ODD) after function entry

main:
  push rbp
;-- stack aligned

or
main:
  sub rsp,3*8
;-- stack aligned


Next, always have EVEN number of pushes(or subtract 8*EVEN) in the code
push rax
push rdx
call somefunc
pop rdx
pop rax

or

sub rsp,4*8
call somefunc
add rsp,4*8



Ok, I'll go ahead and align my stack. I'm curious though, why is it that the stack needs to be 16 byte aligned? What kind of problems are caused if its not, and why?

Thanks,
mikfig
Posted on 2011-09-17 11:57:01 by mikfig
Ok I cleaned it up, make sure push/pops are even and made sure that the stack space I allocated is divisible by 16.
Now it doesn't get a segmentation fault until you use 9 or more arguments. But ya, the segfault is still there.

Fixed code:
# PURPOSE:      This program finds the maximum number of a
#              set of data items.
#

.section .data

hello_msg:

        .asciz "Hello from GAS\n"

current_data_item_msg:

        .asciz "Current data item #%lld: %lld\n"

greatest_data_item:

        .asciz "Greatest data item: %lld\n"

exit_msg:

        .asciz "See ya!!\n"

debug_2:

        .asciz "Mem for args: %lld bytes\n"

.section .text

.globl main

main:

pushq %rbp                              # Create a new stack frame
movq  %rsp, %rbp                        # following C runtime rules
pushq %rsi
pushq %rdi
pushq %rbx
pushq %r9
pushq %r12
pushq %r13
pushq %r14
pushq %r15


addq $8, %rsi                          # program name not an "argument"

#
#
#      INPUTS
#
#      int argc        :      ebx
#      char** argv    :      rsi
#     
#
#      VARIABLES
#
#      stack space for arguments gone through atoll():        rsi
#     

cmpl $2, %edi                          # if no arguments, goto no_args
jl no_args

# previous operation on %edi
# clears higher 32 bits

movq  %rdi, %rbx                        # add enough memory to the stack frame
imulq $8, %rbx                          # to hold all the args and the terminating zero, i.e. argc

movq %rbx, %rax                        # make sure stack reservation is 16-byte aligned
cqto
movq $16, %rcx
idivq %rcx                              # %rbx = argc * 8
addq %rdx, %rbx                        # %rbx = %rbx + (%rbx % 16)

decq %rdi


                pushq %rdi                      # START DEBUG: Print mem needed for args on stack
                pushq %rbx
                pushq %rsi
                pushq %rax

                movq %rbx, %rsi
                movq $debug_2, %rdi
                movq $0, %rax
                call printf

                popq %rax
                popq %rsi
                popq %rbx
                popq %rdi                      # END DEBUG


movq %rdi, %rcx
movq %rsp, %rdi                        # Make room on stack for args
subq %rbx, %rsp                                # put starting address of args in %rdi

movq $0, %rax                          # Going to store args source index in %rax

#
# Go through argv[ i ] and put every argv on the stack
#
# Or if there are no argvs, then just use random numbers
#


# rcx: decrementing counter on number of args left
# rdi: start of stack space for storing args
# rsi: start of pointers to arg strings
# rax: current arg number

arg_loop_start:

        cmpq $0, %rcx
        je arg_quit

                movq  %rax, %r9

                pushq %rcx
                pushq %r9
                pushq %rdi
                pushq %rsi
                pushq %rbx
                pushq $0    # have to push a dummy value to keep stack 16-byte aligned

                movq (%rsi,%rax,8), %rdi
                call atoll                      # 64-bit version of atoi

                popq %rbx
                popq %rbx
                popq %rsi
                popq %rdi
                popq %r9
                popq %rcx

                movq %rax, (%rdi,%r9,8)        # put current arg in stack

                movq %r9, %rax

        incq %rax
        decq %rcx
        jmp arg_loop_start

no_args:

        movl $0, %edi          # Seed random number gen
        call time

        movl %eax, %edi
        call srand

        movq %rsp, %rdi
        subq $48, %rsp          # Make room for 5 random data items + terminating 0
        movq $48, %rbx

        movq $5, %rcx          # Use 5 random data items
        movq $0, %rax

no_args_loop_start:

        cmpq $0, %rcx
        je arg_quit

        movq %rax, %r9

        pushq %rdi
        pushq %rcx
        pushq %r9
        pushq %rbx

        call rand
        addl $1, %eax                  # Make sure its not 0

        popq %rbx
        popq %r9
        popq %rcx
        popq %rdi

        movq %rax, (%rdi, %r9, 8)      # rand putting num in %eax should zero out top 32 bits

        movq %r9, %rax

        incq %rax
        decq %rcx
        jmp no_args_loop_start

arg_quit:

        movq $0, (%rdi, %rax, 8)        # Add the terminating zero

pushq %rdi
pushq %rbx

movq $hello_msg, %rdi
movq $0, %rax
call printf

popq %rbx
popq %rdi

movq %rbx, %rsi
movq $0, %rcx          # Put 0 in the data item index
movq (%rdi), %rbx      # Put the first number in rbx as the largest item

start_data_loop:
        movq (%rdi, %rcx, 8), %rdx

        pushq %rbx
        pushq %rcx
        pushq %rdi
        pushq %rdx
        pushq %rsi
        pushq $0        # 16-byte alignment, pushing junk

        # 3rd argument already in rdx
        movq %rcx, %rsi
        movq $current_data_item_msg, %rdi
        movq $0, %rax
        call printf

        popq %rsi
        popq %rsi
        popq %rdx
        popq %rdi
        popq %rcx
        popq %rbx

        cmpq $0, %rdx
        je data_loop_quit

        cmpq %rdx, %rbx
        jge not_larger

        movq %rdx, %rbx

not_larger:
        incq %rcx
        jmp start_data_loop

data_loop_quit:

        addq %rsi, %rsp        # clean up used stack space

        movq %rbx, %rsi
        movq $greatest_data_item, %rdi
        movq $0, %rax
        call printf

        movq $exit_msg, %rdi
        movq $0, %rax
        call printf

popq %r15              # Destroy the stack frame and exit
popq %r14
popq %r13
popq %r12
popq %rbx              # AMD64 ABI, have to preserve %rbp, %rbx, %r12-%r15
popq %r9
popq %rdi              # Intel386 ABI, have to preserve %rbp, %rbx, %rdi, %rsi
popq %rsi
movq %rbp, %rsp
popq %rbp

ret
Posted on 2011-09-17 15:13:16 by mikfig

movq %rsp, %rdi                        # Make room on stack for args
subq %rbx, %rsp                                # put starting address of args in %rdi

From a quick look it seems rdi points to "[..." area and not to allocated stack area. Exchange those two rows.
Posted on 2011-09-17 15:26:50 by drizz
Ok, I'll go ahead and align my stack. I'm curious though, why is it that the stack needs to be 16 byte aligned? What kind of problems are caused if its not, and why?
It's the standard  ;) ( Win64 ABI requires it also ). IMO it is because floating point arguments are passed in xmm registers and the most efficient store/load instruction requires 16-byte memory alignment. And since SSE2 is implied in x64 and there are other sse2 instructions that require 16byte alignment it reduces the overhead of aligning the stack manually.
Posted on 2011-09-17 16:02:54 by drizz


movq %rsp, %rdi                        # Make room on stack for args
subq %rbx, %rsp                                # put starting address of args in %rdi

From a quick look it seems rdi points to "[..." area and not to allocated stack area. Exchange those two rows.


Haha ya, I was looking over my code again and found the same mistake :P.
It's because later on when I put my data on the stack I was going towards increasing memory addresses.
I was thinking that movq %rax, (%rdi, %r9, 8 ) was subtracting %r9*8 from %rdi for some reason,
wanting to go from the first "allocated address" to the very top of the stack instead of from the top of the stack to the bottom.
So, silly mistake, and that was what was causing this whole segmentation fault.
Overwriting the return address and shooting everything to hell.

Anyways I fixed all my issues and now it works perfectly. I noted the stack before the first instruction in main() is executed
and before the least ret instruction. I did a diff on 800 bytes on the stack and I kept it squeaky clean :).
And all my stack allocations are 16-byte aligned :).
So as far as I can see I guess I obeyed the ABI, but I have to finish reading through that.

So here's the fixed code :):

# PURPOSE:	This program finds the maximum number of a
# set of data items.
#

.section .data

hello_msg:

.asciz "Hello from GAS\n"

current_data_item_msg:

.asciz "Current data item #%lld: %lld\n"

greatest_data_item:

.asciz "Greatest data item: %lld\n"

exit_msg:

.asciz "See ya!!\n"

debug_2:

.asciz "Mem for args: %lld bytes\n"

.section .text

.globl main

main:

pushq %rbp # Create a new stack frame
movq  %rsp, %rbp # following C runtime rules
pushq %rsi
pushq %rdi
pushq %rbx
pushq %r9
pushq %r12
pushq %r13
pushq %r14
pushq %r15


addq $8, %rsi # program name not an "argument"

#
#
# INPUTS
#
# int argc : edi
# char** argv : rsi
#
#
# VARIABLES
#
# stack space for arguments gone through atoll(): rsi
#

cmpl $2, %edi # if no arguments, goto no_args
jl no_args

# previous operation on %edi
# clears higher 32 bits

movq  %rdi, %rbx # add enough memory to the stack frame
imulq $8, %rbx # to hold all the args and the terminating zero, i.e. argc

movq %rbx, %rax # make sure stack reservation is 16-byte aligned
cqto
movq $16, %rcx
idivq %rcx # %rbx = argc * 8
addq %rdx, %rbx # %rbx = %rbx + (%rbx % 16)

decq %rdi


pushq %rdi # START DEBUG: Print mem needed for args on stack
pushq %rbx
pushq %rsi
pushq %rax

movq %rbx, %rsi
movq $debug_2, %rdi
movq $0, %rax
call printf

popq %rax
popq %rsi
popq %rbx
popq %rdi # END DEBUG


movq %rdi, %rcx # Make room on stack for args
subq %rbx, %rsp # put address of first arg in %rdi
movq %rsp, %rdi

movq $0, %rax # Going to store args source index in %rax

#
# Go through argv[ i ] and put every argv on the stack
#
# Or if there are no argvs, then just use random numbers
#

# rcx: decrementing counter on number of args left
# rdi: start of stack space for storing args
# rsi: start of pointers to arg strings
# rax: current arg number

arg_loop_start:

cmpq $0, %rcx
je arg_quit

movq  %rax, %r9

pushq %rcx
pushq %r9
pushq %rdi
pushq %rsi
pushq %rbx
pushq $0    # have to push a dummy value to keep stack 16-byte aligned

movq (%rsi,%rax,8), %rdi
call atoll # 64-bit version of atoi

popq %rbx
popq %rbx
popq %rsi
popq %rdi
popq %r9
popq %rcx

movq %rax, (%rdi,%r9,8) # put current arg in stack

movq %r9, %rax

incq %rax
decq %rcx
jmp arg_loop_start

no_args:

movl $0, %edi # Seed random number gen
call time

movl %eax, %edi
call srand

call rand # Generate a random number of data items
cqto # from 1 to 50
movq $50, %rcx
idivq    %rcx
addq $1,  %rdx

movq %rdx, %r9

addq $1, %rdx # Need room for terminating zero

imulq $8, %rdx # Make sure the stack allocation is 16-byte aligned
movq %rdx, %rbx
movq %rdx, %rax
cqto
movq $16, %rcx
idivq %rcx
addq %rdx, %rbx

subq %rbx, %rsp # Make room for random data items + terminating 0
movq %rsp, %rdi

movq %r9, %rcx # %rcx: counter, %rax: index
movq $0, %rax

no_args_loop_start:

cmpq $0, %rcx
je arg_quit

movq %rax, %r9

pushq %rdi
pushq %rcx
pushq %r9
pushq %rbx

call rand
addl $1, %eax # Make sure its not 0

popq %rbx
popq %r9
popq %rcx
popq %rdi

movq %rax, (%rdi, %r9, 8) # rand putting num in %eax should zero out top 32 bits

movq %r9, %rax

incq %rax
decq %rcx
jmp no_args_loop_start

arg_quit:

movq $0, (%rdi, %rax, 8) # Add the terminating zero

pushq %rdi
pushq %rbx

movq $hello_msg, %rdi
movq $0, %rax
call printf

popq %rbx
popq %rdi

movq %rbx, %rsi
movq $0, %rcx # Put 0 in the data item index
movq (%rdi), %rbx # Put the first number in rbx as the largest item

start_data_loop:
movq (%rdi, %rcx, 8), %rdx

pushq %rbx
pushq %rcx
pushq %rdi
pushq %rdx
pushq %rsi
pushq $0 # 16-byte alignment, pushing junk

# 3rd argument already in rdx
movq %rcx, %rsi
movq $current_data_item_msg, %rdi
movq $0, %rax
call printf

popq %rsi
popq %rsi
popq %rdx
popq %rdi
popq %rcx
popq %rbx

cmpq $0, %rdx
je data_loop_quit

cmpq %rdx, %rbx
jge not_larger

movq %rdx, %rbx

not_larger:
incq %rcx
jmp start_data_loop

data_loop_quit:

addq %rsi, %rsp # clean up used stack space

movq %rbx, %rsi
movq $greatest_data_item, %rdi
movq $0, %rax
call printf

movq $exit_msg, %rdi
movq $0, %rax
call printf

popq %r15 # Destroy the stack frame and exit
popq %r14
popq %r13
popq %r12
popq %r9 # AMD64 ABI, have to preserve %rbp, %rbx, %r12-%r15
popq %rbx
popq %rdi # Intel386 ABI, have to preserve %rbp, %rbx, %rdi, %rsi
popq %rsi
movq %rbp, %rsp
popq %rbp

ret
Posted on 2011-09-17 17:35:57 by mikfig