-1

I'm learning to code in x86-64 assembly (AT&T) on Linux (gcc) and couldn't find a solution to my segmentation fault in this trivial code. I've seen some questions referring to stack alignment; however, this fails even when I try $8 or $16:

.global main
main:

    #prologue
    movq    %rsp, %rbp  #initialise base pointer

    #reserve memory for subroutine
    subq    $8, %rsp   #the line causing the segfault

exit:
    movq    $0, %rdi
    call    exit

My other programs I´ve written seem to work fine after a call to printf. What is wrong with the above code? The code fails with or without the call to exit. This and the code below is failing. I compile using:

gcc -o test test.s

The entire code:

.text
formatStr: .asciz "%ld"
resultStr: .asciz "The result is: %d\n"
q1: .asciz "Enter the base: "
q2: .asciz "Enter the exponent: "

#qTable2: #look up table for correct string during scanf
#   .asciz q1
#   .asciz q2

qTable: #alternative look up table
    .quad base
    .quad exponent

    base:
        movq $q1, %rdi
        ret
    exponent:
        movq $q2, %rdi
        ret

###################
# Subroutine:   pow
# Function: Power an integer base to an exponent
# Inputs:   uint base, int exponent(natural)
# Outputs:  int result
##################
pow:
    #prologue
    pushq   %rbp    #store caller base pointer
    movq    %rsp, %rbp

    movq    $1, %rax    #reset result
    movq    $0, %rbx    #initialise loop    
    loop1:
        imulq   %rdi
        incq    %rbx
        cmp %rsi, %rbx  #compare loop interator to exponent
        jle loop1           

    #epilogue
    movq    %rbp, %rsp  #clear local variables from stack
    pop %rbp    #restore caller base pointer
    ret

.global main
###################
# Subroutine:   Main
# Function:     Application entry point
###################

main:

    #prologue
    pushq   %rbp
    movq    %rsp, %rbp  #initialise base pointer

    #reserve memory for subroutine
    subq    $8, %rsp

    #Gather the inputs from the user
    movq    $0, %rbx    #loop counter

#inputAcq:
    #Call printf using correct question
    movq    %rax, %rsi  #move result into argument 2
    movq    qTable(,%rbx,8), %rdi   #format string as argument 1
    call    *%rdi
    movq    $0, %rax    #no vector registers
    call    printf

    leaq    -16(%rbp,%rbx,8), %rsi  #Argument 2 
    movq    formatStr, %rdi #Argument 1
    movq    $0, %rax    #no vector registers
    call    scanf       

    incq    %rbx    #increment loop counter

    cmp $1, %rbx    #check if more inputs are necessary else continue
    jl  inputAcq

    #Call pow
    movq    -8(%rbp), %rsi  #the exponent
    movq    -16(%rbp), %rdi #the base
    call    pow

    #Call printf
    movq    %rax, %rsi  #move result into argument 2
    movq    $resultStr, %rdi    #format string as argument 1
    movq    $0, %rax    #no vector registers
    call    printf

#exit program without errors
exit:
    movq    $0 , %rdi
    call    exit

The error for the main code when using (gdb) x/i $pc:

0x4004e5 <exit+7>:  callq  0x4004de <exit>
Johann
  • 73
  • 8

2 Answers2

2
exit:                   # target of the CALL instruction
    movq    $0 , %rdi
    call    exit

You've written an infinite loop that includes pushing a return address. It eventually segfaults when you run out of stack.

Use a different name for the exit label in your own code. .Lexit would work, and wouldn't show up as a label when debugging.

See this answer for more about local labels in GNU as syntax.

Community
  • 1
  • 1
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • The code was plagued with other segmentation faults. But that one was the dumbest. Started learning how to use gdb properly to help find my errors quicker. gcc -g at least gives me the line number that causes the fault when running gdb which is why gdb seemed so cryptic to me. But both your comments helped thanks! – Johann Sep 25 '16 at 10:58
  • Note that my answer is also correct (in fact it's more correct given the original question): the actual faulting instruction is `callq 0x4004de` (which tries to push return address onto (now exhausted) stack). You could remove the `subq $8, %rsp` entirely, and you'll still get the fault. – Employed Russian Sep 25 '16 at 16:43
  • @EmployedRussian: yeah, totally agree. No idea why anyone downvoted it. I upvoted it while it was still the only possible answer to the question (before the edit). – Peter Cordes Sep 25 '16 at 19:58
  • @Johann: See also the bottom of the [x86 tag wiki](http://stackoverflow.com/tags/x86/info) for gdb tips – Peter Cordes Sep 25 '16 at 19:59
  • Thanks, I'm definitely going to study that wiki. Already found some interesting topics! @EmployedRussian I wanted to upvote yours but don't have enough rep, since this was my first question. I inadvertently induced different segfaults when trying to reduce my code to a minimal example. This was my first major leap away from the comfort of IDEs. – Johann Sep 26 '16 at 19:44
1

subq $8, %rsp #the line causing the segfault

Since the instruction above does not reference memory, there is no way that segmentation fault is happening on that instruction.

You are likely mis-interpreting what you actually see. You should

  1. show a minimal example, complete with build commands, and
  2. show how you arrived at "the line causing the segfault" conclusion, so your mistake can be pointed out.

P.S. To find the actual instruction on which the segfault happens, run your program under gdb and execute (gdb) x/i $pc command once the segfault actually happens.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
  • When I compile either blocks of code I receive the error . Without the exit in the simplified code, I receive another error 0x0: Cannot access memory at address 0x0. I've also updated my code above. – Johann Sep 25 '16 at 06:45
  • @Johann: If you don't do something to exit, then the CPU just keeps executing whatever is in memory. A string of all-zero bytes happens to decode to a dereference of RAX, if I recall correctly. That's where the `Cannot access memory at address 0x0` comes from, which you'd see if you used the disassembly feature of your debugger. (e.g. `layout asm` / `layout ret`. See the bottom of the [x86 tag wiki](http://stackoverflow.com/tags/x86/info)) – Peter Cordes Sep 25 '16 at 06:58