2012-04-25 62 views
3

雖然我知道最好是使用編譯器內在函數,對於這個問題,printf_chk,也可以將數據放在.rodata部分,我正在研究對彙編語言有更深入的理解,並對壓縮代碼感興趣。有一些關於printf我不明白。我知道把參數放在哪裏,並且我知道如何使用%al作爲可變參數,但它似乎需要額外的堆棧空間,我無法解釋。printf在x86-64上需要額外的堆棧空間嗎?

這套短節目

 .text 
     .globl main 
main: 
     movsd value(%rip), %xmm0 # value to print 
     movl $format, %edi   # format string 
     movl $1, %eax    # one floating-point arg 
     call printf 
     movl $0, %eax    # return 0 from main 
     ret 
     .align 8 
value: .double 74.321 
format: .asciz "%g\n" 

給出了一個段錯誤。

然而,當我添加額外的堆棧空間的框架,它工作正常:

 .text 
     .globl main 
main: 
     subq $8, %rsp    # ADD SOME STACK SPACE TO FRAME (WHY?) 
     movsd value(%rip), %xmm0 # value to print 
     movl $format, %edi   # format string 
     movl $1, %eax    # one floating-point arg 
     call printf 
     movl $0, %eax    # return 0 from main 
     addq $8, %rsp    # REMOVE ADDED STACK SPACE 
     ret 
     .align 8 
value: .double 74.321 
format: .asciz "%g\n" 

難道是對齊問題? (我得到了同樣的問題時valueformat處於.rodata部分。)

+0

http://stackoverflow.com/questions/8691792/how-to-write-assembly-language-hello-world-program-for-64-bit-mac-os-x – 2015-07-08 14:29:45

回答

4

堆棧必須對齊16字節,根據www.x86-64.org/documentation/abi.pdf也是微軟的http://msdn.microsoft.com/en-us/library/ms235286(v=vs.80).aspx

+0

接受!通過將值從8更改爲16並獲得段錯誤進行驗證,然後更改爲24並且不會收到段錯誤。有趣的是,當我使用printf和矢量寄存器時,這種情況只會發生。我沒有看到我的第一個示例工作正常_without_ tweaking rsp和第二個需要調整的區別。關於第二個版本的問題,第一個版本不對齊,第一個版本是什麼? – 2012-04-28 02:25:11

+0

啊,我現在記得:堆棧在main()的開頭對齊了16字節。調用指令將8字節的返回地址壓入堆棧,使堆棧錯位,導致您需要將8個字節的奇數倍重新排列以重新對齊。爲什麼只有當使用矢量寄存器(寄存器!不是堆棧!)時,未對齊的堆棧纔會導致段錯誤,這對我來說並不完全清楚。可能缺乏對可變參數如何工作的理解。 – mattst88 2012-04-28 05:42:26