棧內容很大程度上取決於以下幾點:
- 的CPU
- 編譯
- 調用約定(即參數如何在寄存器和堆棧中傳遞)
- 由編譯器執行的代碼優化
這是我用gcc stk.c -S -o stk.s
使用x86 MinGW的編譯你的小程序獲得:
.file "stk.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "SomeString\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB6:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $32, %esp
call ___main
movl $LC0, 28(%esp)
movl 12(%ebp), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, (%esp)
call _printf
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE6:
.def _printf; .scl 2; .type 32; .endef
而這就是我得到使用gcc stk.c -S -O2 -o stk.s
,就是啓用了優化:
.file "stk.c"
.def ___main; .scl 2; .type 32; .endef
.section .text.startup,"x"
.p2align 2,,3
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
LFB7:
.cfi_startproc
pushl %ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
andl $-16, %esp
subl $16, %esp
call ___main
movl 12(%ebp), %eax
movl 4(%eax), %eax
movl %eax, (%esp)
call _printf
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
LFE7:
.def _printf; .scl 2; .type 32; .endef
正如你所看到的,在後一種情況下,堆棧上沒有指向「SomeString」的指針。事實上,該字符串甚至不在編譯的代碼中。
在這個簡單的代碼中,沒有寄存器保存在堆棧上,因爲沒有任何變量分配給需要在printf()
的調用中保留的寄存器。
所以,你得到的堆棧上的唯一的東西在這裏是字符串指針(可選),未使用的空間由於棧對齊(andl $-16, %esp
+ subl $32, %esp
對齊的堆棧和局部變量分配空間,沒有在這裏),該printf()
「 s參數,從printf()
返回到main()
的返回地址。
在前一種情況下指針「SomeString」和printf()
的參數(的argv[1]
值)是相當遠離彼此:
movl $LC0, 28(%esp) ; address of "SomeString" is at esp+28
movl 12(%ebp), %eax
addl $4, %eax
movl (%eax), %eax
movl %eax, (%esp) ; address of a copy of argv[1] is at esp
call _printf
爲了使兩個地址存儲後的一個正確如果這就是你想要的,你需要使用代碼,編譯/優化選項或者使用不同的編譯器。
或者您可以提供格式字符串argv[1]
,使printf()
可以達到它。例如,您可以在格式字符串中包含多個僞參數。
例如,如果我使用gcc stk.c -o stk.exe
並運行它作爲stk.exe %u%u%u%u%u%u%s
編譯這段代碼,我會從中得到以下的輸出:
4200532268676042006264200532880015253SomeString
所有這一切是相當哈克和它的不平凡的使其正確工作。
這是一個輝煌的答案,謝謝!我在GCC中用'-mpreferred-stack-boundary = 2'編譯它。有了這個,'%s'作爲argv [1]會給我只是「SomeString」。我正在使用GDB,看到堆棧跟蹤,並且在我的編譯中,%s(argv [1])的ptr和字符串的ptr被存儲,然後在進入printf之前存儲RET ptr。 – asudhak