これは私のアセンブリレベルコードです...
section .text
global _start
_start: mov eax, 4
mov ebx, 1
mov ecx, mesg
mov edx, size
int 0x80
exit: mov eax, 1
int 0x80
section .data
mesg db 'KingKong',0xa
size equ $-mesg
出力:
root@bt:~/Arena# nasm -f elf a.asm -o a.o
root@bt:~/Arena# ld -o out a.o
root@bt:~/Arena# ./out
KingKong
私の質問はグローバル_startは何のために使用されますか?私はMr.Googleで運を試しましたが、それが私のプログラムの出発点を伝えるために使われていることがわかりました。なぜ_start
プログラムがどこで開始するかを伝えるために、画面上にちょっとした警告を出す以下のようなもの
section .text
_start: mov eax, 4
mov ebx, 1
mov ecx, mesg
mov edx, size
int 0x80
exit: mov eax, 1
int 0x80
section .data
mesg db 'KingKong',0xa
size equ $-mesg
root@bt:~/Arena# nasm -f elf a.asm
root@bt:~/Arena# ld -e _start -o out a.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
root@bt:~/Arena# ld -o out a.o
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048080
global
ディレクティブはNASM固有です。生成されたオブジェクトコード内のポイントにコード内のシンボルをエクスポートするためのものです。ここでは、_start
シンボルをグローバルとしてマークし、その名前がオブジェクトコード(a.o
)に追加されるようにします。リンカ(ld
)は、オブジェクトコード内のそのシンボルとその値を読み取ることができるため、出力実行可能ファイルのエントリポイントとしてマークする場所がわかります。実行可能ファイルを実行すると、コードで_start
としてマークされている場所から開始されます。
シンボルのglobal
ディレクティブが欠落している場合、そのシンボルはオブジェクトコードのエクスポートテーブルに配置されないため、リンカはそのシンボルを知ることができません。
_start
(デフォルト)とは異なるエントリポイント名を使用する場合、次のようにldに-e
パラメータを指定できます。
ld -e my_entry_point -o out a.o
ラベルは、グローバルであると宣言するまで明示的にグローバルではないため、グローバルディレクティブを使用する必要があります。
グローバルラベル「_start」はリンカに必要です。グローバル_startアドレスがない場合、リンカはそれを見つけることができないので文句を言います。 _startをグローバルとして宣言しなかったため、そのモジュール/コードのオブジェクトの外部からは見えないため、リンカーからは見えません。
これは、ローカルであると宣言しない限り、物事がグローバルであると暗示されるCの反対です。
unsigned int hello;
int fun ( int a )
{
return(a+1);
}
helloとfunはグローバルで、オブジェクトの外側に表示されますが、これは
static unsigned int hello;
static int fun ( int a )
{
return(a+1);
}
ローカルに表示されなくなります。
すべてローカル:
_start:
hello:
fun:
more_fun:
これらは現在、リンカおよびその他のオブジェクトに対してグローバルに利用可能です
global _start
_start:
global hello
hello:
...
__start
_は、デフォルトのld
リンカースクリプトによってエントリポイントとして使用されます
そのリンカスクリプトの関連部分を次のように表示できます。
_ ld -verbose a.o | grep ENTRY
_
どの出力:
_ENTRY(_start)
_
ELFファイル形式 (および他のオブジェクト形式)は、_e_entry
_ヘッダーフィールドを介してプログラムが実行を開始するアドレスを明示的に示します。
ENTRY(_start)
は、オブジェクトファイルからELFファイルを生成するときに、シンボル__start
_のアドレスをそのエントリに設定するようリンカーに指示します。
次に、OSがプログラムの実行を開始すると(Linuxでは exec
システムコール )、ELFファイルを解析し、実行可能コードをメモリに読み込み、設定します指定されたアドレスへの命令ポインター。
by Sedat で言及された_-e
_フラグは、デフォルトの__start
_シンボルをオーバーライドします。
また、デフォルトのリンカースクリプト全体を_-T <script>
_オプションで置き換えることもできます。 hereは、ベアメタルアセンブリのものをセットアップする具体的な例です 。
globalは、ELFファイルでシンボルをグローバルとしてマークするアセンブラディレクティブです
ELFファイルには、可視性を示すすべてのシンボルのメタデータが含まれています。
これを観察する最も簡単な方法は、nm
ツールを使用することです。
たとえば、Linux x86_64 GAS自立型hello worldの場合:
main.S
_.text
.global _start
_start:
asm_main_after_prologue:
/* write */
mov $1, %rax /* syscall number */
mov $1, %rdi /* stdout */
lea msg(%rip), %rsi /* buffer */
mov $len, %rdx /* len */
syscall
/* exit */
mov $60, %rax /* syscall number */
mov $0, %rdi /* exit status */
syscall
msg:
.ascii "hello\n"
len = . - msg
_
コンパイルして実行:
_gcc -ffreestanding -static -nostdlib -o main.out main.S
./main.out
_
nm
の結果:
_00000000006000ac T __bss_start
00000000006000ac T _edata
00000000006000b0 T _end
0000000000400078 T _start
0000000000400078 t asm_main_after_prologue
0000000000000006 a len
00000000004000a6 t msg
_
_man nm
_は次のことを示しています。
小文字の場合、シンボルは通常ローカルです。大文字の場合、シンボルはグローバル(外部)です。
したがって、__global
_は外部から見える(大文字のT
)が、_.global
_としてマークしなかったmsg
は(小文字のt
)。
リンカは 同じ名前の複数のグローバルシンボルが見られる場合の爆破方法を知っています 、または smarter things are more exotic symbolタイプが見られます 。
__start
_をグローバルとしてマークしない場合、ld
は悲しくなり、次のように言います。
エントリシンボル_startが見つかりません
global _start
は、メモリアドレスを指す単なるラベルです。_startの場合、ELFバイナリに関しては、プログラムが開始するアドレスとして機能するデフォルトのラベルが使用されます。
main
または_main
またはmain_
もあり、C言語には既知であり、「通常」リンクされている「スタートアップコード」によって呼び出されます-Cを使用している場合。
お役に立てれば。