在程序集中扫描一个字符指针
Scanf a char pointer in Assembly
所以我有一个任务要做,这需要我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 , %esp
pushl $INPUT_STRING
call printf #printf("Give me a string: ")
addl , %esp
pushl -12(%ebp) # char*
pushl $SCANF_STRING # "%s"
call scanf scanf("%s", char*)
addl , %esp
pushl -12(%ebp)
pushl PRINTF_STRING
call printf #printf("String: %s\n")
addl , %esp
movl -4(%ebp), %ecx
xorl %eax, %eax
leave
leal -4(%ecx), %esp
ret
它首先正确地写下 printf,然后等待输入(因此 scanf
有效),但是当我输入任何内容时 -> Segmentation fault
.
我知道,char*
应该以某种方式初始化,但我如何从汇编级别进行初始化?
我正在 Manjaro 64 位上编译它,gcc -m32
首先,到底是谁跟你说的那些废话:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl , %esp
...
leave
leal -4(%ecx), %esp
ret
这样做:
pushl %ebp
movl %esp, %ebp
subl , %esp # Place for 32 local bytes
andl $-16, %esp # Alignment 16 - not needed for 32-bit programs
...
leave
ret
不仅不需要对齐,而且您还可以使用以下 PUSH
取消对齐堆栈。但随心所欲... ;-)
您想为字符串使用本地堆栈帧的 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 , %esp
mov , %ecx
mov %esp, %edi
mov , %al
rep stosb
pushl $INPUT_STRING
call printf # printf("Give me a string: ")
addl , %esp
leal -12(%ebp), %eax
pushl %eax # char*
pushl $SCANF_STRING # "%s"
call scanf # scanf("%s", char*)
addl , %esp
leal -12(%ebp), %eax
pushl %eax # char*
pushl $PRINTF_STRING ##### '$' was missing
call printf # printf("String: %s\n")
addl , %esp ##### 16 was wrong. Only 2 DWORD à 4 bytes were pushed
leave
ret
所以我有一个任务要做,这需要我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 , %esp
pushl $INPUT_STRING
call printf #printf("Give me a string: ")
addl , %esp
pushl -12(%ebp) # char*
pushl $SCANF_STRING # "%s"
call scanf scanf("%s", char*)
addl , %esp
pushl -12(%ebp)
pushl PRINTF_STRING
call printf #printf("String: %s\n")
addl , %esp
movl -4(%ebp), %ecx
xorl %eax, %eax
leave
leal -4(%ecx), %esp
ret
它首先正确地写下 printf,然后等待输入(因此 scanf
有效),但是当我输入任何内容时 -> Segmentation fault
.
我知道,char*
应该以某种方式初始化,但我如何从汇编级别进行初始化?
我正在 Manjaro 64 位上编译它,gcc -m32
首先,到底是谁跟你说的那些废话:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl , %esp
...
leave
leal -4(%ecx), %esp
ret
这样做:
pushl %ebp
movl %esp, %ebp
subl , %esp # Place for 32 local bytes
andl $-16, %esp # Alignment 16 - not needed for 32-bit programs
...
leave
ret
不仅不需要对齐,而且您还可以使用以下 PUSH
取消对齐堆栈。但随心所欲... ;-)
您想为字符串使用本地堆栈帧的 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 , %esp
mov , %ecx
mov %esp, %edi
mov , %al
rep stosb
pushl $INPUT_STRING
call printf # printf("Give me a string: ")
addl , %esp
leal -12(%ebp), %eax
pushl %eax # char*
pushl $SCANF_STRING # "%s"
call scanf # scanf("%s", char*)
addl , %esp
leal -12(%ebp), %eax
pushl %eax # char*
pushl $PRINTF_STRING ##### '$' was missing
call printf # printf("String: %s\n")
addl , %esp ##### 16 was wrong. Only 2 DWORD à 4 bytes were pushed
leave
ret