0

I want to print out command line arguments out in x86-64 assembly(with AT&T syntax).

This is a followup question to my previous post on how simply to access these arguments. I also wanted to know how to print all command-line arguments to the console.

.globl main
main:
  push %rbp                        # rbp not used, for alignment only
  mov %rsp, %rbp

  mov %edi, %esi                   # move argc to second parameter register
  lea format_string(%rip), %rdi    # the format string is the first parameter
  xor %eax, %eax                   # 0 xmm registers used
  call printf@plt
  xor %eax, %eax                   # return 0 to behave nicely

  mov 16(%rbp), %rsi               # get argv[1] (pointer to first command line argument)
  mov (%rsi), %rdi                 # load the pointer to the first argument into %rdi
  lea arg_format(%rip), %rsi       # load argument format string
  xor %eax, %eax                   # 0 xmm registers used
  call printf@plt

  pop %rbp
  ret

.section .rodata
format_string: .string "Arguments: %d\n"
arg_format: .string "First Argument: %s\n"



Anon
  • 31
  • 3
  • You missed point (1) of Jester's answer to your [previous question](https://stackoverflow.com/questions/76416529/how-to-print-the-number-of-command-line-arguments-in-x86-64-assembly): *That stack layout is for the initial entry point, not main.* Again, compiler output for a C `main` would have made a working example for a normal function like `main`, as opposed to `_start`. (Although if you were writing a `_start`, you have too many dereferences.) See [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) for more about looking at compiler output. – Peter Cordes Jun 06 '23 at 18:20

1 Answers1

3

You're trying to get argv from 16(%rbp) which doesn't make sense. It's not on the stack. It was the second argument to main so it was in %rsi on entry to the function.

Since %rsi is call-clobbered, we need to save it in a call-preserved register across the first printf call. I've chosen %rbx below (%rbp would also have worked). And since it is call-preserved we need to save and restore it at the beginning and end of our main function (this also happens to take care of stack alignment).

Since %rbx points to the start of the argv vector, or in other words its zeroth element argv[0], we have to add 8 to point to argv[1]. So mov 8(%rbx), %rsi will get it for us.

Also, your code had the argument order reversed on the second call to printf.

Here is a fixed version that works for me:

.globl main
main:
        push %rbx                       # %rbx is call preserved
        mov %rsi, %rbx                  # save argv in %rbx
        mov %edi, %esi                  # move argc to second parameter register
        lea format_string(%rip), %rdi   # the format string is the first parameter
        xor %eax, %eax                  # 0 xmm registers used
        call printf@plt

        mov 8(%rbx), %rsi               # argv[1] as second parameter
        lea arg_format(%rip), %rdi      # format string as first parameter
        xor %eax, %eax                  # 0 xmm registers used
        call printf@plt

        xor %eax, %eax                  # NOW this is the return value
        pop %rbx
        ret  

.section .rodata
format_string: .string "Arguments: %d\n"
arg_format: .string "First Argument: %s\n"

If you want to print all the arguments, then you need to write a loop. You could add 8 to %rbx on each iteration to point to the next element of argv. Load it into a register, test whether it is zero (i.e. null pointer), and conditionally jump out of the loop if not; otherwise print it. I'll leave the implementation for you as practice.

Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82