2016-09-24 31 views
-1

我學習到的x86-64彙編代碼(AT & T)在Linux上(GCC)和無法找到這個簡單的代碼解決我的分段故障。我看到一些問題涉及堆棧對齊;

.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 

我的其他程序從來就寫到似乎做工精細後調用printf:然而,當我嘗試$ 8或$ 16本甚至失敗。上面的代碼有什麼問題?該代碼失敗,或不需要退出調用。這和下面的代碼是失敗的。我編譯使用:

gcc -o test test.s 

整個代碼:

.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 

主代碼中的錯誤使用(GDB)X/I $ PC時:

0x4004e5 <exit+7>: callq 0x4004de <exit> 
+2

你的代碼的其餘部分是什麼? – fuz

+0

http://stackoverflow.com/help/mcve – sigjuice

+0

@sigjuice:'[mcve]'在評論中擴展爲[mcve]。另請參閱http://meta.stackexchange.com/questions/92060/add-data-se-style-magic-links-to-comments/94000#94000其他魔術評論降價,如'[問]''。 –

回答

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

你已經寫了一個包含推送返回地址的無限循環。當您用完堆棧時,它最終會出現段錯誤。

在自己的代碼中exit標籤使用不同的名稱。 .Lexit可以工作,並且在調試時不會顯示爲標籤。

更多有關GNU局部標籤的語法見this answer

+0

代碼被其他分段錯誤困擾。但那是最愚蠢的。開始學習如何正確使用gdb以幫助更快地找到我的錯誤。 gcc -g至少給了我運行gdb時導致錯誤的行號,這就是爲什麼gdb對我來說看起來如此神祕。但你的評論都謝謝你! – Johann

+0

請注意,我的回答也是正確的(實際上在給出原始問題時它更爲正確):實際的錯誤指令是「callq 0x4004de」(它試圖將返回地址推送到(現在耗盡的)堆棧上)。你可以完全刪除'subq $ 8,%rsp',你仍然會出錯。 –

+0

@EmployedRussian:是的,完全同意。不知道爲什麼有人低估了它。我對它進行了升級,但它仍然是唯一可能的答案(在編輯之前)。 –

1

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

S因爲上面的指令沒有參考內存,所以有沒辦法那段分割錯誤發生在指令。

您很可能會誤解您實際看到的內容。你應該

  1. 顯示小例子,完整的構建命令,並
  2. 告訴你如何到達「行導致段錯誤」的結論,所以你的錯誤可以指出。

P.S.爲了找到該段錯誤發生在實際指令,gdb下運行您的程序並執行(gdb) x/i $pc命令,一旦段錯誤實際發生。

+0

當我編譯任何代碼塊時,我收到錯誤。如果沒有退出簡化代碼,我會收到另一個錯誤0x0:\t無法訪問地址0x0處的內存。我還更新了上面的代碼。 – Johann

+0

@Johann:如果你不做任何事情退出,那麼CPU只是繼續執行任何內存。如果我記得正確,一串全零字節恰好解碼爲RAX的解引用。這就是'無法訪問地址0x0處的內存'的地方,如果你使用了調試器的反彙編功能,你會發現它。 (例如'layout asm' /'layout ret'。請參閱[x86 tag wiki](http://stackoverflow.com/tags/x86/info)的底部) –