2016-05-04 9 views
2

ファイルからバイト(char)を書き出すcから呼び出される関数をアセンブラで作ってみたい。ここでは関数はCでどのように見えるべきかです:x86アセンブラでファイルにバイトを書き込む

void writebyte (FILE *f, char b) 
{ 
    fwrite(&b, 1, 1, f); 
} 

そして、ここではそれを呼び出すコードは、次のとおりです。

#include <stdio.h> 

extern void writebyte(FILE *, char); 

int main(void) { 
    FILE *f = fopen("test.txt", "w");  
    writebyte(f, 1); 
    fclose(f); 
    return 0; 
} 

これまでのところ私は、次のアセンブラコードを思い付いた:

.global  writebyte 
writebyte: 
    pushl %ebp 
    movl %esp, %ebp #standard params 
    pushl 12(%ebp) # pushing byte to the stack 
    pushl $1 
    pushl $1 
    pushl 8(%ebp)  #file to write 
    call fwrite 
    popl %ebp 
    ret 

私はgdbから得ています。

Program terminated with signal SIGSEGV, Segmentation fault. 
#0 0xffa9702c in ??() 

アセンブリでこのような関数を書くにはどうしたらいいですか?

編集:私はcdecl慣例によると

+1

あなたはアセンブラでライブラリをはstdてきていないので、コードはOSに依存することになります。 – Matt

+0

ubuntuを使用しています。16.04 – polyx

+5

fwriteを呼び出す際の最初のパラメータは、バイト自体を指すのではなく、そのバイトを指すアドレスです。プログラムを正しくリンクしていると仮定すると、fwriteはあなたのバイトをアドレスとして使用しようとしているため、segフォルトが発生している可能性が高く、仮想アドレス空間にマップされていないアドレスのメモリにアクセスします。 –

答えて

3

のUbuntu 16.04を使用しています、あなたは逆の順序で引数をプッシュする必要があります。従ってfが最初に行き、bは最後に行くべきです。また、スタックは、fwrite()を呼び出した後、呼び出し元によってクリーンアップされる必要があります。

コメントに記載されているとおり、bは値として受け取られますが、ポインタとしてfwrite()に渡す必要があります。ポインタは、ebp + 12の値に等しくなります。

これは私のために働くようだ:

.global writebyte 
writebyte: 
    //create new stack frame 
    pushl %ebp 
    movl %esp, %ebp 

    //push the four arguments to stack (in reverse order) 
    pushl 8(%ebp) 
    pushl $1 
    pushl $1 

    //get pointer of "b" argument (%ebp+12) and move it to %eax 
    leal 12(%ebp), %eax 
    pushl %eax 

    //call fwrite() 
    call fwrite 

    //remove arguments from stack and pop %ebp 
    leave 

    ret 
+0

なぜ呼びおよび関数名にアンダースコアを使用しますか? – polyx

+1

私はこの例をコンパイルするためにWindowsを使用していたので、WindowsではGCCにシンボル名がアンダースコアで始まる必要があり、実際にはすべてのC関数にアンダースコアが付加されています。コンパイルされたオブジェクトファイルを逆アセンブルすると分かります。しかし、とにかく、Linuxでは、下線は必要ないので、私はそれらを削除するために投稿を編集します。 –

+0

ありがとう、よく知っています。 – polyx