web-dev-qa-db-ja.com

アセンブリ言語のglobal _startとは何ですか?

これは私のアセンブリレベルコードです...

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
23
vikkyhacks

globalディレクティブはNASM固有です。生成されたオブジェクトコード内のポイントにコード内のシンボルをエクスポートするためのものです。ここでは、_startシンボルをグローバルとしてマークし、その名前がオブジェクトコード(a.o)に追加されるようにします。リンカ(ld)は、オブジェクトコード内のそのシンボルとその値を読み取ることができるため、出力実行可能ファイルのエントリポイントとしてマークする場所がわかります。実行可能ファイルを実行すると、コードで_startとしてマークされている場所から開始されます。

シンボルのglobalディレクティブが欠落している場合、そのシンボルはオブジェクトコードのエクスポートテーブルに配置されないため、リンカはそのシンボルを知ることができません。

_start(デフォルト)とは異なるエントリポイント名を使用する場合、次のようにldに-eパラメータを指定できます。

ld -e my_entry_point -o out a.o
37
Sedat Kapanoglu

ラベルは、グローバルであると宣言するまで明示的にグローバルではないため、グローバルディレクティブを使用する必要があります。

グローバルラベル「_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:
...
5
old_timer

__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
_

GitHubアップストリーム

コンパイルして実行:

_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を使用している場合。

お役に立てれば。

0
Moksh