0

So while I was trying to program something in assembly, I stumbled upon a problem. I'm trying to scan in two variables, using the scanf subroutine, and then printing them both in one sentence, using the printf subroutine. Now this seemed to work on a virtualbox instance(linux) that I'm using, but since I was not sattisfied with the input lag I had with virtualbox, I installed ubuntu 16.04 alongside my original OS, which is windows 10.

So I was all happy with the way my Linux was working, without any input lag. Then I tried to compile and run the same code as in the virtualbox (which worked there!) and for some reason got a "Segmentation fault (core dumped)" error.

If I do the scanf subroutine once and print the input, it works fine. But when I use the scanf subroutine twice, it just stops working after entering 1 value in the terminal.

Can somebody please tell me what's wrong, or what might be wrong/different by using Ubuntu instead of the virtualbox?

Example of my code (comments won't properly stay aligned):

.text
scanner: .asciz "%ld"                                                                               #format string for scanning
output: .asciz "%ld%ld\n"                                                                   #format string for second printing

.global main
main:
    movq    %rsp, %rbp                #initialize basepointer
    call    thing                     #call inout subroutine
    jmp     end                       #jump to end

thing:
    pushq   %rbp                      #basepointer value to stack
    movq    %rsp, %rbp                #basepointer set to stackpointer

    subq    $8, %rsp                  #move rsp up by 8
    leaq    -8(%rbp), %rsi            #allocate memory input
    movq    $scanner, %rdi            #put scanner in rdi
    movq    $0, %rax                  #no vector register in use for scanf
    call    scanf                     #call scanf routine

    subq    $8, %rsp                  #move rsp up by 8
    leaq    -16(%rbp), %rsi           #allocate memory input (under previous one)
    movq    $scanner, %rdi            #put scanner in rdi
    movq    $0, %rax                  #no vector register in use for scanf
    call    scanf                     #call scanf routine

    movq    $output, %rdi             #put output in rdi 
    movq    -8(%rbp), %rsi            #set input value in rsi
    movq    -16(%rbp), %rdx           #set second input value in rdx
    movq    $0, %rax                  #no vector register in use for printf
    call    printf                    #call the printf routine

    movq    %rbp, %rsp                #clean the stack 
    popq    %rbp                      #reset basepointer
    ret                               #return to main

end:
    movq    $0, %rdi                  #load program exit code
    call    exit                      #exit the program

Thanks in advance!

Mithras
  • 65
  • 1
  • 9
  • `main` clobbers its caller's `rbp`, because you didn't save/restore it. Is that intentional because you call `exit` instead of returning? (`jmp end` and putting that way at the bottom after the end of a different function is really weird.) – Peter Cordes Sep 26 '18 at 21:27
  • You also misalign the stack for at least one of the scanf calls (not 16-byte aligned). Which instruction segfaults? Is it inside scanf? If so, it's a duplicate of [scanf Segmentation faults when called from a function that doesn't change RSP](https://stackoverflow.com/q/51070716): even without a non-zero `%al`, scanf in recent builds of glibc faults if you don't follow the ABI requirement of 16-byte stack alignment before a `call`. – Peter Cordes Sep 26 '18 at 21:31
  • What is `mystring`? Please provide http://stackoverflow.com/help/mcve – Employed Russian Sep 27 '18 at 02:56
  • Whoops, that wasn't supposed to be in there, I edited it out. – Mithras Sep 27 '18 at 05:38
  • @Peter Cordes, so what you are saying is that I should increase the number which I substract from the RSP, from 8 to 16? (As you can see, I'm not experienced at all, hence why the code might be a bit messy) – Mithras Sep 27 '18 at 05:43
  • Reserve enough space to reach a 16-byte boundary and leave space for both locals that you want to pass by reference to scanf. Look at compiler-generated code for example to see how gcc or clang do it. Once you know they're aiming for a 16-byte boundary, you can see why they sometimes leave an extra 8 bytes unused. – Peter Cordes Sep 27 '18 at 05:46
  • Alright, I gave the second scanf more room by moving the stackpointer down by 16 instead of 8 the second time. It seems to work now, though since I have to run this in the virtualbox for school, is there a way to change the glibc version just for the assembly programming? (Ubuntu GLIBc 2.27-3ubuntu1 is installed, I want to use Debian GLIBC 2.24-11+deb9u3) – Mithras Sep 27 '18 at 09:14

0 Answers0