2017-04-22 10 views
-2

私には、scanfchar*というアセンブリが必要な作業があります。私はこのコードを試してみました:アセンブリ内の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 

それは私が何も入力したときに、それは、入力(そうscanf作品)を待って、しかし、正しく最初のprintfダウン書き込み - >Segmentation faultを。

私は、char*は何とか初期化する必要がありますが、どのようにアセンブリレベルから行うことができますか?

私は地獄はがらくたことを告げたすべてのgcc -m32

答えて

1

まず、で、Manjaro 64ビットでそれをコンパイルしています:

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バイトの開始アドレスが必要です。その領域のアドレスはコンパイル時には分かりません。 -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

関連する問題