0

I'm trying to print the number of command line arguments that are present in an Assembly program in x86-64.

It's from my understanding that argument information is stored on the stack.

I feel like I'm missing something fundamental on how to retrieve items stored from the stack but I don't know exactly what.

enter image description here

.file "args.s"

.globl main
.type main, @function

.section .data
format_string:
  .string "Argument: %s\n"

.section .text
main:
  pushq %rbp
  movq %rsp, %rbp

  popq %rsp                   ; get argc
  movq %rsp, %rdi             ; move argc to rdi, first parameter register
  movq $format_string, %rdi   ; pass in the string to be used and give the parameter
  call printf                 

  leave
  ret
.size main, .-main 
Anon
  • 31
  • 3
  • 3
    You have 6 problems (at least). 1) that stack is for the initial entry point, not `main` 2) you are popping the `rbp` you just pushed and not anything already on the stack 3) you pop into `rsp` which will bite you later 4) while `main` also gets `argc`, the 64 bit calling convention does not pass it on the stack 5) you try to pass `argc` in `rdi` when it should be `rsi` as it is the second argument to `printf` and 6) your format string tries to print `argc` as a string – Jester Jun 06 '23 at 16:13
  • Look at compiler output (https://godbolt.org/) for a C `main` function that does `printf("%d\n", argc)`. Godbolt has dropdown option to have it use AT&T syntax (like you are) instead of Intel. [How to remove "noise" from GCC/clang assembly output?](https://stackoverflow.com/q/38552116) – Peter Cordes Jun 06 '23 at 16:19
  • Thanks for the website. I don't see any option for AT&T syntax? – Anon Jun 06 '23 at 16:44
  • @Anon: Don't forgot to @ notify people so they see your replies. It's in the "output" dropdown in the compiler pane, at the top left of the part that has the asm compiler output. e.g. https://godbolt.org/z/asPxzEKEj – Peter Cordes Jun 06 '23 at 18:38

1 Answers1

5

You have the following problems (at least):

  1. That stack layout is for the initial entry point, not main.
  2. You are popping the rbp you just pushed and not anything already on the stack.
  3. You pop into rsp (the stack pointer), which will bite you later: push / pop and call / ret instructions use rsp as a pointer.
  4. While main also gets argc as an argument, the 64 bit calling convention does not pass it on the stack.
  5. You try to pass argc in rdi when it should be rsi as it is the second argument to printf. Since int is 32 bit you can use esi.
  6. printf tries to interpret argc as a string because you used %s instead of %d in the format string.
  7. You do not zero %al for printf (this is not fatal in practice since it only needs to be an upper bound so any value in there should work, in non-ancient builds of libc. Older GCC computed an indirect jump so AL values above 8 could crash.)

Optional: your code is not position independent which is recommended (and sometimes required) in modern systems. You can put your format string into .rodata as it is read only.

A fixed version could look like:

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

  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
 
  pop %rbp
  ret

.section .rodata
format_string: .string "Arguments: %d\n"
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Jester
  • 56,577
  • 4
  • 81
  • 125
  • Thank you. How do you also print out the command line arguments? Is it just lea format_string 8(%rip), %rdi ? and then calling printf@plt? Also can you explain this command printf@plt? – Anon Jun 06 '23 at 16:41
  • No, of course not. The `format_string` is the format string, there is nothing to offset there. You will need to access `argv` which is passed as the second argument to `main` in `rdi`. `printf@plt` is just a way to call `printf` in a way suitable for PIE. – Jester Jun 06 '23 at 18:51