質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

Q&A

1回答

1444閲覧

アセンブリ がセグフォになってしまうのはなぜですか?

mitokyo

総合スコア0

アセンブリ言語

アセンブリ言語とは、機械語を人間にわかりやすい形で記述した低水準言語です。

0グッド

1クリップ

投稿2020/10/03 02:44

前提・実現したいこと

アセンブリ言語で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です
ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2020/10/03 02:49

なぜですか?と聞かれたら、間違ってるからです。としかこたえようがないですが そのコードはなにをしようとしてるんでしょうか。そこらへん解説しましょう で、しつもんはなんでしょうか
mitokyo

2020/10/03 03:56

c言語のread関数と同じ動きをする関数をアセンブリ 言語で書きました。 read関数がエラーを起こす場合、 例えばファイルディスクリプターが適切ではない場合、read先のアドレスがNULLの場合など エラーメッセージを表示させるにはerrornoに正しい値を入れる必要があります。 その際、質問に載せた二つのコードを試しました。 前者ではセグメンテーションフォールトを起こしましたが …で以降のコードではerrornoに正しい値が入り、エラーメッセージを perror("");で表示させることができました。 二つのコードの異なる点は systemcallのエラー時の返り値を持つraxの値を 前者ではr8に、後者ではpushしてメモリに保持した点です。 同じように別の場所に保持していたのに、 なぜr8レジスタに保持した場合は失敗するのか?というのが質問です。
hidezzz

2020/10/03 05:41 編集

x64のアセンブラあまり分かっているわけではないのですが…、 > アセンブリ言語でread関数の再現しました。 my_readサブルーチンはread関数の機能の再現は出来てないように見えるのですが、それは今回の質問では本題では無いということで良いでしょうか? (my_read関数の引数をreadシステムコールで規定されているレジスタに代入する処理が無いように見えるのですが、都合よく関数の引数が変換無しでシステムコールに渡されるようなレジスタ並びになっているんでしたっけ?) コアダンプさせる設定になっていればコアダンプからセグメント違反した箇所が特定出来ると思うので、まずどこでどのように落ちたか確認すると良いかと思います。
mitokyo

2020/10/03 06:28

my_read(fds, NULL, 90); で rdi = fds rsi = NULL rdx = 90 となります。 syscall時には システムコール番号:rax=3 第一引数:rdi=fds 第二引数:rsi=NULL 第三引数:rdx=90 と値が入ってるので代入する処理は必要はないとおもうのですが。 認識が間違っていたらすみません。
hidezzz

2020/10/03 07:24

なるほど。 read()(とそれを模したmy_read())とシステムコールの間で入力のレジスタをそのまま渡せるように考慮されたデザインになっているということなんですね。であれば問題ないと思います。 繰り返しになってすみませんが、落ちた箇所の特定が必要じゃないでしょうか。(___error内部で落ちてるのか、戻ってきてから落ちているのか、…)
guest

回答1

0

アセンブリコードはまず横に置いといて、

my_read(fds, NULL, 90);

おそらくこれはなにかを読み込む関数(のつもり)でしょうけど、
なにを、どこに、どれだけ読み込むのか説明できますか。

投稿2020/10/03 03:00

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mitokyo

2020/10/03 03:24

NULLにfdsにはいっているファイルディスクリプターのファイルから90文字読み込む関数です。 今回の場合、 test.txtファイルをNULLに90文字読み込むようにしています。 NULLなのでエラーとして errornoにBad addressを示す値が返されます。 エラー内容をperror("");で出力しています。
y_waiwai

2020/10/03 03:26

で、そのNULLのときにエラーにするという処理はどこにあるんでしょうか
mitokyo

2020/10/03 03:30

_my_read: mov rax,0x2000003 syscall ;cflag ga tatu jc error ここでエラーがあればerrorに飛びます ret error:  飛んだ先がこちらです。戻り値は−1を返しています。 push rax call ___error pop rcx mov QWORD[rax], rcx mov rax, -1 ret
y_waiwai

2020/10/03 03:33

ざんねんながらそれでエラーにはなりません
mitokyo

2020/10/03 03:41

エラーになりませんとはどのような意味ですか? ここでerrno にエラーの原因を示す値を設定され、 動いているのを確認しているのですが
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問