gpt4 book ai didi

linux - Scanf 汇编中的 char 指针

转载 作者:太空宇宙 更新时间:2023-11-04 05:42:46 24 4
gpt4 key购买 nike

所以我有一个任务要做,这需要我在汇编中scanf一个char*。我尝试了这段代码:

.data
INPUT_STRING: .string "Give me a string: "
SCANF_STRING: .string "%s"
PRINTF_STRING: .string "String: %s\n"

.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $32, %esp
pushl $INPUT_STRING
call printf #printf("Give me a string: ")
addl $4, %esp
pushl -12(%ebp) # char*
pushl $SCANF_STRING # "%s"
call scanf scanf("%s", char*)
addl $8, %esp
pushl -12(%ebp)
pushl PRINTF_STRING
call printf #printf("String: %s\n")
addl $16, %esp
movl -4(%ebp), %ecx
xorl %eax, %eax
leave
leal -4(%ecx), %esp
ret

它正确地写下第一个 printf,然后等待输入(因此 scanf 可以工作),但是当我输入任何内容时 -> 段错误

我知道,char* 应该以某种方式初始化,但是我如何从程序集级别执行此操作?

我正在 Manjaro 64 位上使用 gcc -m32 编译它

最佳答案

GCC's stack-alignment code进入 main 过于复杂:

leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $32, %esp
...
leave
leal -4(%ecx), %esp
ret

这样做:

pushl %ebp
movl %esp, %ebp
subl $32, %esp # Space for 32 local bytes
andl $-16, %esp # Alignment by 16
...
leave
ret

现代 Linux 上使用的 i386 System V ABI 版本确实保证/要求在调用之前进行 16 字节堆栈对齐,因此您可以通过 3 次推送(包括 push %ebp)而不是 and 重新对齐。与 x86-64 不同,大多数 i386 库函数不会被编译为在其堆栈空间中的局部变量上使用 movaps 或 movdqa 16 字节对齐加载/存储,因此您通常可以像在 scanf 之前使用 PUSH es 那样取消堆栈对齐。 (不过,当您第一次调用 printf 时,ESP % 16 == 0;这是正确的。)

<小时/>

您想要将本地堆栈帧的 12 个字节用于字符串。 scanf 需要这 12 个字节的起始地址。该区域的地址在编译时未知。 -12(%ebp) 为您提供该地址处的值,而不是地址本身。 LEA是计算地址的指令。因此,您必须插入此指令以在运行时获取地址并将其传递给 C 函数:

leal -12(%ebp), %eax
pushl %eax # char*

这是工作示例(也纠正了小错误):

.data
INPUT_STRING: .string "Give me a string: "
SCANF_STRING: .string "%11s" ##### Accept only 11 characters (-1 because terminating null)
PRINTF_STRING: .string "String: %s\n"

.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $32, %esp

mov $32, %ecx
mov %esp, %edi
mov $88, %al
rep stosb

pushl $INPUT_STRING
call printf # printf("Give me a string: ")
addl $4, %esp

leal -12(%ebp), %eax
pushl %eax # char*
pushl $SCANF_STRING # "%s"
call scanf # scanf("%s", char*)
addl $8, %esp

leal -12(%ebp), %eax
pushl %eax # char*
pushl $PRINTF_STRING ##### '$' was missing
call printf # printf("String: %s\n")
addl $8, %esp ##### 16 was wrong. Only 2 DWORD à 4 bytes were pushed

leave
ret

关于linux - Scanf 汇编中的 char 指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43565363/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com