2017-04-22 83 views
-2

所以我有一个任务要做,这需要从我到scanf a组装char*。我想这样的代码:Scanf在组件中的字符指针

.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作品),但后来当我输入任何内容 - >Segmentation fault

我知道,char*应该以某种方式初始化,但是我怎样才能从程序集级别上做到这一点?

我编译它Manjaro 64位,与gcc -m32

回答

1

首先,到底是谁告诉你的废话:

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  # Place for 32 local bytes 
andl $-16, %esp  # Alignment 16 - not needed for 32-bit programs 
... 
leave 
ret 

的不仅不需要对齐,而且您可以使用以下的PUSH es对齐堆栈。但有你的方式...... ;-)

你想使用12个字节的本地堆栈帧的字符串。 scanf需要这12个字节的起始地址。编译时不知道该区域的地址。 A -12(%ebp)为您提供此地址的值,而不是地址本身。 LEA是计算地址的指令。所以,你必须插入这个指令来获取ADDRES在运行时,并把它传递给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 
+0

但那么,你在'-12(%ebp)'上放了一个'char *',如果它有很长的长度呢?它在哪里存储所有的字符? – Frynio

+0

@Frynio:在堆栈中。这是“subl $ 32,%esp”的一部分。对于一个非常大或可变的长度,您可以像使用C一样使用'malloc'。如果您使用的是C库 - 请像C程序员那样考虑:-) – rkhb

+0

是的,我知道。但是,字符数量的限制是什么? – Frynio