前提・実現したいこと
アセンブリ言語でread関数の再現しました。
前者のコードでは
fdに適当な番号をあたえたり、読み込み先のアドレスをNULLにしたときに、
セグメンテーションフォールトが起きてしました。
後者のコードでは
−1を返して終了します。
前者のコードでは別のレジスタにsystemcallから
RAXに返されたエラーナンバーを退避させています。
後者ではメモリに退避させています。
前者と後者では何が違うのでしょうか?
発生している問題・エラーメッセージ
エラーメッセージ zsh: segmentation fault
該当のソースコード
ソースコード extern ___error section .text global _my_read _my_read: mov rax,0x2000003 syscall ;cflag ga tatu jc error ret error: mov r8, rax call ___error mov QWORD[rax], r8 mov rax, -1 ret ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ extern ___error section .text global _my_read _my_read: mov rax,0x2000003 syscall ;cflag ga tatu jc error ret error: push rax call ___error pop rcx mov QWORD[rax], rcx mov rax, -1 ret
試したこと
このように試していました
#include <stdio.h> #include <string.h> #include <errno.h> extern ssize_t ft_read(int fildes, void *buf, size_t nbyte); int main(int argc, char **argv) { int fd = open("./test.txt", O_RDONLY); char buf[100]; char sbuf[100]; read(fd, NULL, 90); perror(""); printf("read:\n%s\n", buf); close(fd); int fds = open("./test.txt", O_RDONLY); my_read(fds, NULL, 90); perror(""); // perror(""); // printf("ft_read:\n%s\n", sbuf); close(fds); }
ここに問題に対して試したことを記載してください。
補足情報(FW/ツールのバージョンなど)
Intel x64です
ここにより詳細な情報を記載してください。
なぜですか?と聞かれたら、間違ってるからです。としかこたえようがないですが
そのコードはなにをしようとしてるんでしょうか。そこらへん解説しましょう
で、しつもんはなんでしょうか
c言語のread関数と同じ動きをする関数をアセンブリ 言語で書きました。
read関数がエラーを起こす場合、
例えばファイルディスクリプターが適切ではない場合、read先のアドレスがNULLの場合など
エラーメッセージを表示させるにはerrornoに正しい値を入れる必要があります。
その際、質問に載せた二つのコードを試しました。
前者ではセグメンテーションフォールトを起こしましたが
…で以降のコードではerrornoに正しい値が入り、エラーメッセージを
perror("");で表示させることができました。
二つのコードの異なる点は
systemcallのエラー時の返り値を持つraxの値を
前者ではr8に、後者ではpushしてメモリに保持した点です。
同じように別の場所に保持していたのに、
なぜr8レジスタに保持した場合は失敗するのか?というのが質問です。
x64のアセンブラあまり分かっているわけではないのですが…、
> アセンブリ言語でread関数の再現しました。
my_readサブルーチンはread関数の機能の再現は出来てないように見えるのですが、それは今回の質問では本題では無いということで良いでしょうか?
(my_read関数の引数をreadシステムコールで規定されているレジスタに代入する処理が無いように見えるのですが、都合よく関数の引数が変換無しでシステムコールに渡されるようなレジスタ並びになっているんでしたっけ?)
コアダンプさせる設定になっていればコアダンプからセグメント違反した箇所が特定出来ると思うので、まずどこでどのように落ちたか確認すると良いかと思います。
my_read(fds, NULL, 90);
で
rdi = fds
rsi = NULL
rdx = 90
となります。
syscall時には
システムコール番号:rax=3
第一引数:rdi=fds
第二引数:rsi=NULL
第三引数:rdx=90
と値が入ってるので代入する処理は必要はないとおもうのですが。
認識が間違っていたらすみません。
なるほど。
read()(とそれを模したmy_read())とシステムコールの間で入力のレジスタをそのまま渡せるように考慮されたデザインになっているということなんですね。であれば問題ないと思います。
繰り返しになってすみませんが、落ちた箇所の特定が必要じゃないでしょうか。(___error内部で落ちてるのか、戻ってきてから落ちているのか、…)