2

次のコードが与えられます:

    .section    .rodata
str:    .string "Hello World!\n"
input:  .long 2
    ########
    .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp

    pushl   $str
    call    printf

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret

出力は「HelloWorld!」になります。


今、私はユーザーから番号を取得し、それを画面に印刷しようとしましたが、それは機能しません(コードコンパイル、しかし私は何か間違ったことをしました)。私の間違いはどこにありますか?

    .section    .rodata
input:  .long   2
    ########
    .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp
    pushl   %ebx    

    call    scanf  # call scanf to get number from the user
    popl    input  # store the number entered by user in input (variable)
    pushl   input  # push it back into the stack
    call    printf # print input

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret
4

2 に答える 2

4

使用しているアセンブラの種類はよくわかりませんが、コードをgccでコンパイルできるので、フォーマットスタイルに固執しました(AT&T構文については説明していません)。

とにかく、ドキュメントをチェックして、読み取られた値を格納する場所のメモリ内の場所へのフォーマット文字列ポインタscanfが必要であることを理解する必要があります。また、読み取られたものではなく、正常に読み取られたアイテムの数が返されます。

次に同じことを行い、ドキュメントで。を確認しますprintf。数値を読み取り可能な形式で印刷するには、フォーマット文字列が必要であることがわかります。適切なフォーマット文字列は"%d\n"、数値と改行を出力することです。

これで、コードは次のようになります(gccでコンパイルして正常に動作します)。

.section .rodata

input_format:  .string  "%d"
output_format: .string  "%d\n"

.section .bss
input:  .long  0          # reserve 4 bytes of space

.section .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp

    pushl   $input    # push the ADDRESS of input to have the value stored in it
    pushl   $input_format   # give scanf the ADDRESS of the format string
    call    scanf    # call scanf to get number from the user
    addl    $8, %esp # clean up the stack
    
    # Note the return value of scanf is passed through eax (same for printf)
    
    pushl   input    # pass the number to printf BY VALUE
    pushl   $output_format  # pass the ADDRESSS of the output format string to printf
    call    printf   # print input

    #return 0 from main:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret

私は通常、andではなくandセクションにメモリを割り当てるために使用することに注意してください。そのためdb/dw/dd、その部分が少し間違っている場合は、修正することができます。.(ro)data.bss.string.long

番号を格納するためにスタックスペースを使用することもできますが、すでにinput宣言しているので、コードをできるだけ同じままにしておきたいと思いました。前後のすべてについても同じことが言えますがscanfprintf私はそれをコードとして残しました。

編集:.bssまたは.dataセグメントで変数を宣言するのではなく、スタックを使用してローカル変数を作成する例を次に示します。

.section .rodata

input_format:  .string  "%d"
output_format: .string  "%d\n"

.section .text
.globl  main
    .type main, @function
main:
    pushl   %ebp
    movl    %esp,   %ebp

    subl    $4, %esp       # allocate 4 bytes on the stack for a local variable

    # The local variable will be at -4(%ebp)

    leal    -4(%ebp), %eax # get the ADDRESS of our local variable
    pushl    %eax          # push the ADDRESS of the variable on the stack
    pushl   $input_format  # give scanf the ADDRESS of the format string
    call    scanf          # call scanf to get number from the user
    addl    $8, %esp       # clean up the stack

    # Note the return value of scanf is passed through eax (same for printf)

    pushl   -4(%ebp)       # pass the number to printf BY VALUE
    pushl   $output_format # pass the ADDRESSS of the output format string to printf
    call    printf         # print the input

    #return from printf:
    movl    $0, %eax
    movl    %ebp,%esp
    popl    %ebp
    ret
于 2011-12-16T05:51:07.950 に答える
3

の引数scanfが正しくない場合は、スキャン形式とバッファの両方をプッシュして、探しているタイプを保持する必要があります。次に、文字列でない場合は、新しい形式の文字列をにプッシュする必要があります。printfこの場合は"%d"

少しこのようになります(Intel / MASM形式で申し訳ありません):

SUB ESP,4 ;make stack space for an int
LEA EAX,[ESP]
PUSH EAX
PUSH offset NumberString ;"%d"
CALL scanf
PUSH [ESP+8] ;our scanned number
PUSH offset NumberString ;"%d"
CALL printf
ADD ESP,20 ;clean up for the cdecl funcs and the alloc'ed stack space
于 2011-12-16T05:46:56.433 に答える