[解決済み] アセンブリで文字列の長さを表示する方法
質問内容
以下のHello Worldプログラムを使用して、アセンブリを学習しています。
section .text
global _start ;must be declared for linker (ld)
_start: ;tells linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
section .data
msg db 'Hello, world!', 0xa ;our string
len equ $ - msg ;length of our string
私が最初に抱いた疑問は、文字列の長さとは何を意味するのか、ということでした。文字数なのか、メモリ上の長さ(バイト数)なのか。 これを確認するために、私は変数lenを表示したいと思いました。どうすればいいのだろう?私は素朴に、新しい変数を定義しようとしました
len2 equ $ - len
を実行し、その代わりに
mov edx,len2 ;message length
mov ecx,len ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
を実行して len を表示しようとしましたが、これでは何も表示されません。どうすれば、lenで表される数値を表示できるのでしょうか?
どのように解決するのですか?
...
mov edx,len ;message length
これは
edx
を何らかの数値で指定します。この例では14です。
len
は定数記号で、次のようなものです。
#define
C言語の場合
mov ecx,msg ;message to write
これは
ecx
のアドレスで、最初の文字 (
msg
はラベルで、メモリを指している)。
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
...
msg db 'Hello, world!', 0xa ;our string
これは14バイトのメモリを定義しており、値は72('H')、101('e')、......です。最初のバイトは
msg
ラベル(それのメモリアドレス)。
len equ $ - msg ;length of our string
これは、定数
len
コンパイル時に表示されます。これはメモリの内容を定義しないので、実行ファイルや実行中に見つけることはできません。
mov edx,len
もちろん、その特定の命令にコンパイルされます)。
定義は
$ - msg
は、その
$
は、次に定義されたマシンコードのバイトがコンパイルされる場所であるカレントアドレスとして機能します。
msg + 14
(文字数を正しく数えられたでしょうか :) ) 。そして
((msg+14) - msg) = 14
= の定義までの間にメモリ上に定義されたバイト数。
len
とラベル
msg
.
ASMはより低レベルなので、メモリやバイトにラベルを付ける方がより正確な表現になりますし、微妙な違いを認識するのに役立つと思うので、変数や文字という言葉を避けていることに注目してください。
あなたの
len2 equ $ - len
の後に
len
は、このように値を定義しました。
len2
として
(msg+14)
(によって新たに追加されたバイトはありません。
len
定義) マイナス
len
というのは
14
を定義しているので、実質的には
len2
と同じです。
msg
.
では
mov edx,len2 ;message length
mov ecx,len ;message to write
...
を呼び出します。
sys_write
と等しい文字列へのポインタを持つ
14
(無効なメモリ参照で、そのメモリ領域は通常のユーザーコードではアクセスできない)、長さは、アドレス
msg
これは、32bのLinuxでは、非常に高い確率で、次のような値になります。
0x80004000
つまり、2Gを超える文字数が出力されることになります。
は、その
sys_write
は当然それを好まず、失敗し、エラーコードを
eax
.
でコンソールに何かを出力する場合
sys_write
の場合、まずASCII(UbuntuのシェルではデフォルトでUTF8がサポートされていると思いますが、確認するのが面倒なので)エンコードされた文字列としてメモリに書き込んで、それを
sys_write
のアドレスと長さ(bytesとcharsの違いは重要です)を指定します。
sys_write
は文字を認識せず、バイナリファイルとバイトを扱うので、長さはバイト数です)。
数字を出力するコードは数行になってしまうので書きません(簡略化した
printf
の実装)、SOではこの件に関して何度かQ+Aを行っていますが、私の説明で何が起きたのか、どのように動作するのかを理解していただければ幸いです。
ASMを学び始めたばかりの方は、以下のどちらかを検討してみてください。
clib
を持つようにする。
printf
文字列の出力は、最初の算数や基本的なフロー制御、スタックの操作よりも少し高度なトピックです。基本的な命令の動作やデバッグの仕方に慣れてきたら、数値の出力に挑戦するのも楽になるでしょう。
関連
-
[解決済み】テスト %eax %eax のポイント【重複あり
-
[解決済み】andiとoriはこのプログラムで何をするのですか?
-
[解決済み】MARIEアセンブリ言語で`Skipcond`はどのように動作しますか?
-
[解決済み] ARMはSDIVとUDIVを区別していますが、ADD、SUB、MULでは区別していないのはなぜですか?
-
[解決済み] cmovlオペコードの中で何と何が比較されるのですか?
-
[解決済み] x86アセンブリで160x100モードを実現する
-
[解決済み] アセンブリで文字列の長さを表示する方法
-
[解決済み] LC3 LEA 命令と格納された値
-
[解決済み] ESPレジスタとEBPレジスタとは何ですか?
-
[解決済み] Collatz予想の検証を行うC++のコードは、なぜ手書きのアセンブリよりも高速に動作するのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン