0

I am trying to get scanf to work. I've been looking at past posts and I am not sure what I am doing wrong. I am able to enter a number but it always segfaults before the next line executes. I think the issue lies on me not understanding how to align the stack to be in multiples of 16.

I keep getting "no such file or directory" a thousand times before it lets the user ask for input. I am not sure if this relates to the issue but just something to point out.

Keep in mind, I am also calling scanf in a loop.

I currently want to store 3 things in the stack: 2 arguments (of the current function, not scanf's) + 1 integer (place to store user input).

Here is what I have so far:

    sub $48, %rsp # allocate space for rdi, rsi, input in multiples of 16
    mov %rdi, 24(%rsp) # store first arg
    mov %rsi, 8(%rsp) # store second arg
    push $0 # %rsp stores the user input, initialized as 0.
    ...
loop:
    mov $0, %rax
    mov $stringFormat, %rdi
    mov %rsp, %rsi
    call scanf
    ...

Here is what the stack looks like before scanf

(gdb) x/12w $rsp
0x7fffffffdfa0: 0       0       4199021 0
0x7fffffffdfb0: 800     0       4198944 0
0x7fffffffdfc0: 5       0       4198480 0
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
daloca7144
  • 11
  • 1
  • 2
    That is not a [mcve]. What you showed should work. It does here. The problem is elsewhere. – Jester Feb 15 '22 at 11:33

1 Answers1

2

Below you find an example written in Intel Assembler (not gcc), which reads a number using scanf and then outputs the number using printf. I didn't add any kind of error checking just to keep the example clean. If I write assembler programs, I usually use nasm/sasm, but it shouldn't be magic to convert it into any other dialect.

; when using SASM, the next, commented out, include will be helpful
; %include "/usr/share/sasm/include/io64.inc"

default rel

section .data
    align 8
    fmt    db "%d",0      ; format for reading an int, zero terminated
    prtfmt db "%d", 10, 0 ; format for printing ending with nl, zero terminated
    
section .bss
    target resq 1         ; a quad to store the result    
    
section .text
global CMAIN

scanfcall:
    push rbp              ;
    mov  rbp, rsp         ; mainly for stack alignment
    
    lea  rdi, [fmt]
    lea  rsi, [target]
    xor  rax, rax         ; this sets the number of floating point arguments to zero
    call scanf
    pop  rbp
    ret

CMAIN:
    push rbp
    mov  rbp, rsp          ; for correct debugging
    
    call scanfcall
    
    ; check if read correctly
    lea  rdi, [prtfmt]
    mov  rsi, qword [target]
    xor  eax, eax         ; set al to zero to indicate no floating point arguments
    call printf
    
    pop  rbp              ; clean up stack
    xor  rax, rax         ; set exit code to zero
    ret

Since you want to use scanf somewhere in a function, so did I.

Ronald
  • 2,842
  • 16
  • 16
  • 1
    It's not necessary to NULL-terminate scanf's arg list. It uses the format string to figure out how many args to look at. Just `xor eax,eax` would be fine to zero the full RAX including AL. Also, you forgot `default rel` to make it useful to use LEA for addresses; this is not just "intel" syntax, it's NASM. And strangely you're using `mov r64, imm64` instead of (hopefully RIP-relative) LEA for the printf format string - see [How to load address of function or label into register](https://stackoverflow.com/q/57212012) – Peter Cordes Feb 15 '22 at 18:57
  • 1
    @PeterCordes Thank you for your comment. As a matter of fact I'm still learning, which is why I liked and answered this question. At the same time I've been experimenting with `lea` instead of `mov` but didn't understand the exact difference. Your answer link helped me to get a better, abeit not total, understanding. I've modified and tested my source (it worked). I hope my change resolves your issues. – Ronald Feb 16 '22 at 10:53
  • Yup, answering SO questions is a good way to learn; I've definitely learned plenty of stuff from people commenting on my answers, that's half of why I commented. Looks mostly good, although you're missing an `xor eax,eax` before `call printf`. (And yes, I do mean EAX, not RAX; [it's a waste of a byte of machine code to use RAX when implicit zero-extension to 64-bit will get the job done](https://stackoverflow.com/questions/38303333/the-advantages-of-using-32bit-registers-instructions-in-x86-64).) – Peter Cordes Feb 16 '22 at 11:14
  • Also getting rid of `io64.inc` would be useful to make it self-contained code. – Jester Feb 16 '22 at 13:08
  • @Jester I've commented out the include. This way it'll be easy to add it for those who use SASM, but won't be in the way for others. – Ronald Feb 16 '22 at 13:15