DOBON.NETプログラミング道掲示板

■34804 / 親記事)  アセンブリ言語について。
  
□投稿者/ コルム 一般人(4回)-(2021/06/30(Wed) 15:20:52)
  • アイコン環境/言語:[Linux] 
    分類:[.NET] 

    これが何をしているのか教えていただけないでしょうか?すみません。
    これの事です。
    (機械語データ) (アセンブリ言語)
    b8 57 61 6b 61 mov $0x616b6157,%eax
    53 push %ebx
    50 push %eax
    ba 04 00 00 00 mov $0x4,%edx
    bb 01 00 00 00 mov $0x1,%ebx
    b8 04 00 00 00 mov $0x4,%eax
    89 e1 mov %esp,%ecx
    cd 80 int $0x80
    58 pop %eax
    31 c0 xor %eax,%eax
    5b pop %ebx
    c3 ret
マルチポストを報告
違反を報告
引用返信 削除キー/
■34807 / ResNo.1)  Re[1]: アセンブリ言語について。
□投稿者/ 魔界の仮面弁士 大御所(1363回)-(2021/06/30(Wed) 18:54:33)
  • アイコンNo34804に返信(コルムさんの記事)
    > 環境/言語:[Linux] 
    > 分類:[.NET] 
    > (アセンブリ言語)

    Linux + .NET + アセンブリですか?
    もしかして、分類:[その他]の間違いでしょうか。

    .NET Core における IL アセンブリのコードというわけでもなさそうですし…。
    https://en.wikipedia.org/wiki/List_of_CIL_instructions


    > (機械語データ) (アセンブリ言語)
    専門外な上に、手元に環境も無いので机上デバッグですが:

    > b8 57 61 6b 61 mov $0x616b6157,%eax
    最初に即値 $0x616b6157 'Waka' を eax レジスタに転送して…

    > 53 push %ebx
    ebx レジスタを使いたいので、元の値をスタックに退避しておく

    > 50 push %eax
    eax に書き込んだ値をスタックに積む

    > ba 04 00 00 00 mov $0x4,%edx
    > bb 01 00 00 00 mov $0x1,%ebx
    > b8 04 00 00 00 mov $0x4,%eax
    eax/ebx/edx それぞれに即値を代入して

    > cd 80 int $0x80
    この時点でシステムコール番号 4 になっているので、
    標準出力に "Waka" の 4 文字が出力されるんじゃないですかね。

     eax: 0x00000004 システムコール番号 write()
     ebx: 0x00000001 write()第1引数:出力先…0x1 なので「標準出力」
     ecx: esp の内容 write()第2引数:出力データのアドレス
     edx: 0x00000004 write()第3引数:出力データのサイズ

    > 58 pop %eax
    出力データはもう不要なのでスタックから取り除いて eax に入れて

    > 31 c0 xor %eax,%eax
    eax 自身を 0 クリア

    > 5b pop %ebx
    最初に退避しておいた ebx を復元して元に戻す

    > c3 ret
    スタックにある同一セグメントのアドレスに戻る
違反を報告
引用返信 削除キー/
■34808 / ResNo.2)  Re[2]: アセンブリ言語について。
□投稿者/ コルム 一般人(5回)-(2021/07/01(Thu) 04:47:55)
  • アイコン>>58 pop %eax
    > 出力データはもう不要なのでスタックから取り除いて eax に入れて
    何の出力データが不要なのでしょうか?教えていただけないでしょうか?すみません。

違反を報告
引用返信 削除キー/
■34809 / ResNo.3)  Re[2]: アセンブリ言語について。
□投稿者/ コルム 一般人(6回)-(2021/07/01(Thu) 04:51:28)
  • アイコン>>c3 ret
    > スタックにある同一セグメントのアドレスに戻る
    同一セグメントのアドレスに戻るという所が分かりません。教えていただけないでしょうか?すみません。
違反を報告
引用返信 削除キー/
■34810 / ResNo.4)  Re[3]: アセンブリ言語について。
□投稿者/ 魔界の仮面弁士 大御所(1364回)-(2021/07/01(Thu) 10:16:47)
  • アイコン結局これは、.NET の話なのでしょうか。それとも分類の選択ミス?

    No34808に返信(コルムさんの記事)
    > 教えていただけないでしょうか?すみません。
    こちらも、コルムさんの質問を見るまでは、x86 アセンブリを
    勉強したことがまったく無いです…。
    .NET の MSIL アセンブリなら、多少齧ったことがあるのですけれども、
    それ以外のアセンブリに関する知識は持ち合わせていません。

    Linux に関する知識も皆無で、昨日小一時間ググって調べた程度の知識しか
    持っていませんが、そんな知ったかぶりでも良ければ。


    >>> 58 pop %eax
    >> 出力データはもう不要なのでスタックから取り除いて eax に入れて
    > 何の出力データが不要なのでしょうか?
    スタックに積みっぱなしで放置するわけにもいかないですよね。
    スタックに push したデータは、pop で取り出して元に戻します。


    ……そもそも『スタック』って分かりますか?

    stack とは「堆積」の意。コンピューター的には Last-In-Last-Out なメモリ管理を指します。
    お皿を積み重ねて保管している場合、最初に取り出せるのは最後にのせたお皿です。
    そして一番上のお皿を取り除かないと、その次のお皿を使うことはできません。

    push は、データというお皿を積み重ねる行為。
    pop とは、積み重ねた一番上のお皿を取り出す行為。

    積み重ねたデータは esp (Extended Stack Pointer) にて管理されており、
    esp は今どこのスタック領域を使っているかを指し示しています。

    下記の「ステップ実行」を使うと、イメージが掴みやすいかと思います。
    https://vanya.jp.net/os/x86call/


    No34809に返信(コルムさんの記事)
    >>> c3 ret
    >> スタックにある同一セグメントのアドレスに戻る
    > 同一セグメントのアドレスに戻るという所が分かりません。

    たとえば A から B を呼び出して、さらにその B から C を呼び出すような場合、
    処理が終わったら呼び出し開始位置に戻ってくる必要があるわけで、
    その場所を示すためにもスタックが使われます。

    戻り先のアドレスをスタックに積んでから、次の処理を呼び出します。
    そこからさらに別の処理を呼ぶ場合も、同様に戻り先をスタックに積んでから呼びます。

    それぞれの処理が終わったら、最後にスタックから直前の「皿」を一枚取り出せば、
    戻り先のアドレスを得る事ができ、それを用いて呼び出し元に戻ることができます。
    https://okwave.jp/qa/q9895314.html

    各関数のスタック領域のベース位置を示しているのが、ebp (Extended Base Pointer) 。
    https://note.com/nekotricolor/n/n2a247c808275


    >>> cd 80 int $0x80
    >> この時点でシステムコール番号 4 になっているので、
    >> 標準出力に "Waka" の 4 文字が出力されるんじゃないですかね。

    文字列が出力されるという話は、この分野に素人な私の想像に過ぎません。

    INT 命令すなわち割り込み(software interrupt)については、
    No34802 で Heiki さんが書かれていたように、
    eax の値によって振る舞いが変わります。


    昨日ググって見つけたのは下記の資料。
    これにより、システムコール番号 4 が write であると知りました。
    https://qiita.com/kure/items/5a1a114f9a37aeab255c

    で、今日改めて調べてみたら、下記の資料を発見。
    https://www.mztn.org/lxasm64/x86_x64_table.html

    これによれば、write のシステムコール番号は
    32bit だと 4 で良いのですが、64 bit だと 1 らしいです。
    そしてシステムコール番号 4 は、32bit だと write ですが、
    64 bit だと stat になるそうです。

    なので、今回の質問が 32bit/64bit のいずれかで話が変わるのでしょうが、
    それを判断するすべを私は持ち合わせていません。(32bit で良いのですかね?)

    …でもって、じゃぁ write だと仮定して、その時の引数はどう扱われるのか
    調べてみたのが、昨日見つけたこの資料の 表3.2。
    https://www.atmarkit.co.jp/ait/articles/1703/01/news172.html

    これを、コルムさんのソースに当てはめてみて、
    >> eax: 0x00000004 システムコール番号 write()
    >> ebx: 0x00000001 write()第1引数:出力先…0x1 なので「標準出力」
    >> ecx: esp の内容 write()第2引数:出力データのアドレス
    >> edx: 0x00000004 write()第3引数:出力データのサイズ
    という動作になるんじゃないか…と想像しました。
    https://kazmax.zpp.jp/cmd/w/write.2.html

    なお今回の処理の場合、eax/ebx/ecx/edx レジスタは
     eax: 初期値不明 → int 段階では 4 → ret 段階では 0
     ebx: 初期値不明 → int 段階では 1 → ret 段階では実行前の ebx 値に復帰
     ecx: 初期値不明 → int 段階では 0x616b6157 を書き込んだポインタ → ret 時点でもそのまま
     edx: 初期値不明 → int 段階では 4 → ret 段階でも 4 のまま
    のように変化します。
違反を報告
引用返信 削除キー/
■34822 / ResNo.5)  Re[3]: アセンブリ言語について。
□投稿者/ コルム 一般人(7回)-(2021/07/05(Mon) 16:58:09)
  • アイコンecx: esp の内容 write()第2引数:出力データのアドレス
    espの内容は何になるのでしょうか?教えていただけると幸いです。すみません。
    それと、# Cの文字列はヌル終端で"Waka"は5バイトになるので
    # 完全には一緒じゃないけど、やりたいことは同じ
    の所で、なぜ5バイトになるのでしょうか?教えていただけると幸いです。すみません。
違反を報告
引用返信 削除キー/
■34823 / ResNo.6)  Re[4]: アセンブリ言語について。
□投稿者/ 魔界の仮面弁士 大御所(1368回)-(2021/07/05(Mon) 18:16:16)
  • アイコンNo34822に返信(コルムさんの記事)
    > それと、# Cの文字列はヌル終端で"Waka"は5バイトになるので
    > # 完全には一緒じゃないけど、やりたいことは同じ
    > の所で、

    えぇと?

    『の所で』とありますが、一体何の話をされているのでしょうか。
    質問文や今回のやり取りには、そんな話は無かったと思うのですが…。

    出典があるのなら、まずは情報ソースを明確にしてください。


    > ecx: esp の内容 write()第2引数:出力データのアドレス
    > espの内容は何になるのでしょうか?教えていただけると幸いです。すみません。

    esp の内容は 'Waka' を指し示すポインタとなっています。

    先に紹介した URL にも書かれている通り、スタックでは、
    esp レジスタにてデータの格納場所が決まります。

    下記の[ステップ実行]ボタンから、push や pop 命令が実行された時に
    esp がどのように変化するか確認してみてください。
    https://vanya.jp.net/os/x86call/

    標準出力に渡すデータは ecx で指定する必要があるため、
    >>> 89 e1 mov %esp,%ecx
    によって、スタック位置を示す esp 値を ecx に取り出しています。


    > なぜ5バイトになるのでしょうか?
    いや、それは話が逆なのでは?

    4 バイトのアセンブリが 5 バイトのデータになる、という話ではなく、
    5 バイトのデータを扱う C 言語のコードをコンパイルしたら、
    4 バイトのデータが処理されるアセンブリが生成された…
    という状況であろうと推察します。出典を見ないと分かりませんが。

    今回提示されたアセンブリには null データが無かったために、
    あくまでも推測ですが、NULL 終端な "Waka\0" という 5 バイトの
    C 言語の文字列データあったとすれば、それは ASCII で

    'W' … 0x57
    'a' … 0x61
    'k' … 0x6B
    'a' … 0x61
    '\0'… 0x00

    というバイナリになりますよね。


    バイナリとして標準出力に出力するのであれば 5 バイト全て必要となりますが、
    テキストとして扱うなら、終端直前までの 4 バイトのみが必要データなので、
    5 バイト目の 0x00 まで push する必要が無く、0x616b6157 の 4 バイトのみで
    結果的には同じ出力結果が得られている…という話なのだと思います。
違反を報告
引用返信 削除キー/
■34824 / ResNo.7)  Re[5]: アセンブリ言語について。
□投稿者/ コルム 一般人(8回)-(2021/07/05(Mon) 20:46:53)
  • アイコン以下のURLは、No.3です。
    https://oshiete.goo.ne.jp/qa/12435650.html
    なぜespがWakaを指し示すのでしょうか?教えていただけると幸いです。すみません。
    あなたの貼った一通りURL見てみます。ありがとうございます。
違反を報告
引用返信 削除キー/
■34825 / ResNo.8)  Re[6]: アセンブリ言語について。
□投稿者/ 魔界の仮面弁士 大御所(1369回)-(2021/07/05(Mon) 21:08:06)
  • アイコンNo34824に返信(コルムさんの記事)
    > なぜespがWakaを指し示すのでしょうか?

    質問するだけでなく、どこまで理解したかもフィードバックしてください。
    どこから説明すれば良いのか困ってしまいます。


    そもそも、冒頭で eax に "Waka" をセットしていることは分かりますか?
    No34823 で示した各文字の対応と見比べてみてください。

    b8 57 61 6b 61 mov $0x616b6157,%eax


    その後、eax の内容をスタックに積んでいますよね。
    この時点で、esp が指し示しているのは "Waka" のポインタになります。
    50 push %eax


    そして esp を ecx に転送しています。
    89 e1 mov %esp,%ecx
    http://programmer.main.jp/assembler/2_1.html

    これにより、ecx が指し示すのは "Waka" のポインタになります。
違反を報告
引用返信 削除キー/
■34826 / ResNo.9)  Re[6]: アセンブリ言語について。
□投稿者/ コルム 一般人(9回)-(2021/07/05(Mon) 21:50:32)
  • アイコンすみません、こういう事でしょうか?
    まず、eaxにWakaを格納して、ecxはpushのeaxがあって、espは一番上にあるものを指すので、 2番目のpushのeaxは 2番目に積まれているスタック( 1番上)にあるから、ecxはWakaというのを指しているという解釈でしょうか?教えていただけると幸いです。すみません。自分なりの考えですが。よろしくお願いします。

違反を報告
引用返信 削除キー/

次のレス10件>

スレッド内ページ移動 / << 0 | 1 | 2 >>

このスレッドに書きこむ

Mode/  Pass/


- Child Tree -