バイナリまたはプログラムは、マシンコードとデータの両方で構成されています。この場合、ソースコードに入れた文字列、コンパイラだけでもバイトだけのデータ、それがどのように使用されたのかは読み込み専用データと見なされます。したがって、.rodataまたは.textになる可能性のあるコンパイラまたはコンパイラが使用する可能性がある別の名前です。 Gccはおそらくそれを.rodataと呼ぶでしょう。プログラム自体は.text形式です。リンカーが表示され、リンクすると、.text、.data、.bss、.rodata、その他のアイテムがある場所を見つけてから接続します。 printfの呼び出しの場合、リンカーは文字列、バイト配列をどこに置いているのかを知っていて、その名前(何らかの内部一時的な名前は間違いない)とその名前についてprintf呼び出しに伝えられたリンカは、printfを呼び出す前に、アドレスをフォーマット文字列に取り込む命令をパッチします。
Disassembly of section .text:
0000000000400430 <main>:
400430: 53 push %rbx
400431: bb 0a 00 00 00 mov $0xa,%ebx
400436: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40043d: 00 00 00
400440: bf e4 05 40 00 mov $0x4005e4,%edi
400445: e8 b6 ff ff ff callq 400400 <[email protected]>
40044a: 83 eb 01 sub $0x1,%ebx
40044d: 75 f1 jne 400440 <main+0x10>
40044f: 31 c0 xor %eax,%eax
400451: 5b pop %rbx
400452: c3 retq
400453: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40045a: 00 00 00
40045d: 0f 1f 00 nopl (%rax)
Disassembly of section .rodata:
00000000004005e0 <_IO_stdin_used>:
4005e0: 01 00 add %eax,(%rax)
4005e2: 02 00 add (%rax),%al
4005e4: 48 rex.W
4005e5: 65 6c gs insb (%dx),%es:(%rdi)
4005e7: 6c insb (%dx),%es:(%rdi)
4005e8: 6f outsl %ds:(%rsi),(%dx)
4005e9: 2c 20 sub $0x20,%al
4005eb: 77 6f ja 40065c <__GNU_EH_FRAME_HDR+0x68>
4005ed: 72 6c jb 40065b <__GNU_EH_FRAME_HDR+0x67>
4005ef: 64 21 00 and %eax,%fs:(%rax)
コンパイラは、この命令をエンコードされたが、リンカが後でそれを埋めることができるように、おそらくゼロまたは一部が
400440: bf e4 05 40 00 mov $0x4005e4,%edi
を埋めるように、アドレスを残しています。 gnu逆アセンブラは意味をなさない.rodata(と.dataなど)ブロックを逆アセンブルしようとします。したがって、アドレス0x4005e4で始まるあなたの文字列を解釈しようとしている命令は無視してください。
オブジェクトの分解をリンクする前に
Disassembly of section .text.startup:
0000000000000000 <main>:
0: 53 push %rbx
1: bb 0a 00 00 00 mov $0xa,%ebx
6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
d: 00 00 00
10: bf 00 00 00 00 mov $0x0,%edi
15: e8 00 00 00 00 callq 1a <main+0x1a>
1a: 83 eb 01 sub $0x1,%ebx
1d: 75 f1 jne 10 <main+0x10>
1f: 31 c0 xor %eax,%eax
21: 5b pop %rbx
22: c3 retq
0000000000000000 <.rodata.str1.1>:
0: 48 rex.W
1: 65 6c gs insb (%dx),%es:(%rdi)
3: 6c insb (%dx),%es:(%rdi)
4: 6f outsl %ds:(%rsi),(%dx)
5: 2c 20 sub $0x20,%al
7: 77 6f ja 78 <main+0x78>
9: 72 6c jb 77 <main+0x77>
b: 64 21 00 and %eax,%fs:(%rax)
がリンクされていないが、リンカーのオフセットこのアドレスは/後を埋めるためにちょうどパッドを有し、.textセクションと.rodataの二つの部分を示しています。
10: bf 00 00 00 00 mov $0x0,%edi
また、オブジェクトには.rodataの文字列のみが含まれています。ライブラリや他のアイテムとリンクして完全なプログラムにするためには、もっと多くの.rodataを明示的に追加しましたが、リンカはそのすべてを管理します。この例オブジェクト
Disassembly of section .text:
0000000000000000 <fun>:
0: 8b 35 00 00 00 00 mov 0x0(%rip),%esi # 6 <fun+0x6>
6: 8b 3d 00 00 00 00 mov 0x0(%rip),%edi # c <fun+0xc>
c: ba 07 00 00 00 mov $0x7,%edx
11: e9 00 00 00 00 jmpq 16 <fun+0x16>
Disassembly of section .data:
0000000000000000 <b>:
0: 05 .byte 0x5
1: 00 00 add %al,(%rax)
...
Disassembly of section .rodata:
0000000000000000 <c>:
0: 07 (bad)
1: 00 00 add %al,(%rax)
...
、あなたは.bssセクションを参照して、それをリンクする必要が何らかの理由として解体
void more_fun (unsigned int, unsigned int, unsigned int);
unsigned int a;
unsigned int b=5;
const unsigned int c=7;
void fun (void)
{
more_fun(a,b,c);
}
で見ることがおそらく
容易になります。この例のポイントは、関数のマシンコードは.text、初期化されていないグローバルは.bss、初期化されたグローバルは.data、const初期化されたグローバルは.rodataです。コンパイラは、グローバルであってもconstを知っても分かりませんでしたので、その値を数学にハードコーディングするだけで、RAMから読み込む必要はありませんが、RAMから読み込まなければならない他の2変数は命令を生成しますリンク時にリンカによって記入されるアドレスのゼロを使用します。
あなたの場合、読み取り専用の/ constデータはバイトの集合であり、それはあなたのソースファイルで定義されたバイトがprintfの最初のパラメータとして指し示されるように、数学演算ではありませんでした。
バイナリにはマシンコードだけではありません。そして、コンパイラとリンカは、マシンコードが取得するメモリに配置されたものを持つことができます。マシンコード自体は、残りのマシンコードで使用されるすべての値を書き込む必要はありません。
バイナリにあります。OSがプログラムを起動したとき、プログラムのマシンコードと同じように、メモリにロードされています。 '[esp]'は 'esp'と同じではないことに注意してください。前者はメモリにアクセスし、' esp'自体は変更しません。 – Jester
メモリにロードされます。私は、その文字列のメモリアドレスが '0x8048441'で始まり、' 0x80484e0'で終わると仮定しています。文字列は整数のリストです。 – Xorifelse
@Jesterああ、 "mov DWORD PTR [esp]、0x80484e0"は実際にespが新しいアドレスを指し示すのではなく、現在指しているアドレスに0x80484e0を書き込むだけですか? –