使用C调用约定,程序集中的堆栈参数正在消失



我目前正在编写一些x86汇编代码,并使用asld将其与glibc链接。

.section .data
str1:
.asciz "n"
str3:
.asciz "Hello"
str4:
.asciz "Goodbye"
str5:
.asciz "Guten Tag!"
str6:
.asciz "Guten Morgen!"

.section .bss
.section .text
.globl _start
_start:
call main
movl %eax, %ebx
movl $1, %eax
int $0x80
# void writeLine(char*);
.type writeLine, @function
writeLine:
pushl %ebp
movl %esp, %ebp
movl $str1, %ecx
pushl %ecx
movl 8(%ebp), %ecx
pushl %ecx
call strcat
movl %eax, %ecx
pushl %ecx
call puts
popl %ebx
.leaver1:
movl %ebp, %esp
popl %ebp
ret
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
movl $str3, %ecx
pushl %ecx
call writeLine
popl %ebx
movl $str4, %ecx
pushl %ecx
call writeLine
popl %ebx
movl $str5, %ecx
pushl %ecx
call writeLine
popl %ebx
movl $str6, %ecx
pushl %ecx
call writeLine
popl %ebx
.leaver3:
movl %ebp, %esp
popl %ebp
ret

问题是,正如预期的输出:

Hello
Goodbye
Guten Tag!
Guten Morgen!

我得到:

Hello
Guten Tag!

通过一些更深入的调试,当我做这样的printf时,参数似乎正在消失:

pushl 8(%ebp)   # Argument for writeLine
pushl $str7     # "Argument for writeLine: %sn"
call printf     # printf();

它显示了">消失";论点什么都没有,比如:

# should be "Goodbye"
Argument for writeLine: 

同样,当我以%d的格式打印出参数时,我最终会得到一个常数,它只会随着我传递的字符串(str3str4等(而变化。

示例:134525414

我还试着将它与gcc(gcc -m32 -S main.c(在编译一个应该做完全相同事情的程序时生成的程序集进行比较,除了gcc生成的东西之外,我无法快速查看代码。

看起来,我的论点正在消失。

strcat(str3, str1)通过从str3的终止空字节开始将str1的字节复制到内存中,将str1连接到str3的末尾。因此,str3的终止null被字符'n'覆盖,并且新的终止null写入下一个字节。但你猜怎么着:紧接在str3终止null之后的字节是str4的第一个字节。所以您刚刚用一个空字节覆盖了str4的第一个字节。因此,当您稍后打印它时,它的行为就像一个空字符串。

您可以在每个字符串之间添加一个额外的空间字节来避免这种情况。但更广泛地说,writeLine函数修改它传递的字符串并不是很明智,所以更好的计划是重新设计它,这样它就不需要这么做了。例如,您可以通过一次对puts的调用来编写传递的字符串(它已经附加了一条换行符(,如果您想要一条额外的换行符,则可以单独调用putc

最新更新