質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.51%

  • C

    4528questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • コンパイラ

    37questions

    コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。

ダイナミックリンカローダーについて

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,040

strike1217

score 568

ダイナミックリンカローダについてです。
動的なリンカ
動的なリンカ/ローダ

ELFファイルフォーマットの先頭には _startがあります。.textセクションに入っているやつですね。 ・・・(1)

_start → __libc_start_main() → main() に入ります。

カーネルがプログラムの起動時にダイナミックリンカローダを起動します。
私の環境では以下のようになっていました。

ダイナミックリンカローダ : /lib/x86_64-linux-gnu/ld-2.24.so 
共有ライブラリ : /lib/x86_64-linux-gnu/libc.so.6    
(間違っていたらご指摘お願いします。)

ELFインタプリタ /lib/x86_64-linux-gnu/ld-2.24.so のエントリアドレスは _startになっていまいます。

このエントリアドレスの_startとは 上記の(1)のことですか?
つまり、ダイナミックリンカローダー → _start → __libc_start_main() → main() ということですかね?
それともこのダイナミックリンカローダの_startとはまた別物ですか??

/lib/x86_64-linux-gnu/ld-2.24.so は直接実行することができます。
普段はカーネルが実行しますが・・・

これとldコマンドとの違いはなんですか?
ld コマンドはアセンブルされた機械語にセクションのマージなどを施すだけでしょうか?
つまり、gcc source.c -o source とやった段階のプリリンカみたいな?
という理解で正しいでしょうか??
(ldと/lib/x86_64-linux-gnu/ld-2.24.soは別物)
リンクについてです。
C/C++のオブジェクトファイルをldコマンドでリンクする方法

名前が紛らわしいので間違っていたらご指摘お願いします。

「追記」
ダイナミックリンカローダーの役割は、共有ライブラリをメモリにロードし実行ファイルの先頭アドレスに移動することですか?
他にも役割があったら教えてください

「追記2」___________________________
このエントリアドレスの_startとは 上記の(1)のことですか?
全くの別物でした。

では、ダイナミックリンカローダーにコンテキストスイッチが行われたあと、どうやってELFファイルの_startに飛んでいるんでしょうか??
%ripレジスタをカウントしていけば自然と_startの中に入るんですか??

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

_start については質問のポイントがわからなくなりましたが、

  • ダイナミンクリンカローダもELFファイルフォーマットです
  • ダイナミンクリンカローダにも、それがロードしようとしている実行可能ファイルにも _start はあります(つまり、メモリ空間上に_startとマークされているアドレスが二箇所あります)

主にこの二点を理解されていないのではないかと思います。

これとldコマンドとの違いはなんですか?

この質問には力が抜けます。。。

  • .o をたくさん集めて実行可能ファイルや共有ライブラリを作る(ファイルを吐き出す)のが ld
  • 実行可能ファイルと共有ライブラリをメモリ空間上にロードし、GOTとかを書き換えて実行できるようにするのがダイナミンクリンカローダ

全然違いますよね。

/lib/x86_64-linux-gnu/ld-2.24.so は直接実行することができます。

これは、トリビア的な話なので、気にしない方がいいと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/18 18:44

    あ、やはり別物ですね。
    名前が似ていたもので・・・・

    「ダイナミンクリンカローダにも、それがロードしようとしている実行可能ファイルにも _start はあります」
    ELFファイルフォーマット形式には_startが個別に用意されているんですね!!

    実行ファイルのエントリポイントを探し出したので後で載せておきますね。

    キャンセル

  • 2017/07/18 18:47

    ldは共有ライブラリを作成するためだけのものではないですよね。
    プリリンクにも使用できるよ!ってことですね!!

    キャンセル

  • 2017/07/18 18:56

    リンクという処理に着目して混乱されているようですが、ld はファイルを吐き出し、これをダイナミンクリンカローダが読み込んでメモリ上に展開すると考えてください。役割が全く異なりますよね。

    キャンセル

  • 2017/07/18 19:18

    gcc source.c -o source とやれば自動的にldが使用されているんですよね。
    ダイナミックリンカローダの出番は実行時ということですよね。

    キャンセル

0

_lib/x86_64-linux-gnu/ld-2.24.so にある_startには
_dl_start()がありました。

_start:\n\                                         
        # Note that _dl_start gets the parameter in %eax.\n\                                           
        movl %esp, %eax\n\                         
        call _dl_start\n\                          
_dl_start_user:\n\                                 
        # Save the user entry point address in %edi.\n\                                                
        movl %eax, %edi\n\                         
        # Point %ebx at the GOT.\n\                
        call 0b\n\                                 
        addl $_GLOBAL_OFFSET_TABLE_, %ebx\n\       
        # See if we were run as a command with the executable file\n\                                  
        # name as an extra leading argument.\n\    
        movl _dl_skip_args@GOTOFF(%ebx), %eax\n\   
        # Pop the original argument count.\n\      
        popl %edx\n\                               
        # Adjust the stack pointer to skip _dl_skip_args words.\n\                                     
        leal (%esp,%eax,4), %esp\n\                
        # Subtract _dl_skip_args from argc.\n\     
        subl %eax, %edx\n\                                 
        push %edx\n\                               
        # The special initializer gets called with the stack just\n\                                   
        # as the application's entry point will see it; it can\n\                                      
        # switch stacks if it moves these contents over.\n\                                            
" RTLD_START_SPECIAL_INIT "\n\                     
        # Load the parameters again.\n\            
        # (eax, edx, ecx, *--esp) = (_dl_loaded, argc, argv, envp)\n\                                  
        movl _rtld_local@GOTOFF(%ebx), %eax\n\     
        leal 8(%esp,%edx,4), %esi\n\               
        leal 4(%esp), %ecx\n\                      
        movl %esp, %ebp\n\                         
        # Make sure _dl_init is run with 16 byte aligned stack.\n\                                     
        andl $-16, %esp\n\                         
        pushl %eax\n\                              
        pushl %eax\n\                              
        pushl %ebp\n\
        pushl %esi\n\
        # Clear %ebp, so that even constructors have terminated backchain.\n\
        xorl %ebp, %ebp\n\
        # Call the function to run the initializers.\n\
        call _dl_init\n\
        # Pass our finalizer function to the user in %edx, as per ELF ABI.\n\
        leal _dl_fini@GOTOFF(%ebx), %edx\n\
        # Restore %esp _start expects.\n\
        movl (%esp), %esp\n\
        # Jump to the user's entry point.\n\
        jmp *%edi\n\
        .previous\n\
");
・・・

if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)])                        
    {                                              
      /* Relocate ourselves so we can do normal function calls and                                     
         data access using the global offset table.  */                                                

      ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0, 0);                                                  
    }                                              
  bootstrap_map.l_relocated = 1;                   

  /* Please note that we don't allow profiling of this object and                                      
     therefore need not test whether we have to allocate the array                                     
     for the relocation results (as done in dl-reloc.c).  */                                           

  /* Now life is sane; we can call functions and access global data.                                   
     Set up to use the operating system facilities, and find out from                                  
     the operating system's program loader where to find the program                                   
     header table in core.  Put the rest of _dl_start into a separate                                  
     function, that way the compiler cannot put accesses to the GOT                                    
     before ELF_DYNAMIC_RELOCATE.  */              
  {                                                
#ifdef DONT_USE_BOOTSTRAP_MAP                      
    ElfW(Addr) entry = _dl_start_final (arg);      
#else                                              
    ElfW(Addr) entry = _dl_start_final (arg, &info);                                                   
#endif                                             

#ifndef ELF_MACHINE_START_ADDRESS                  
# define ELF_MACHINE_START_ADDRESS(map, start) (start)                                                 
#endif                                             

    return ELF_MACHINE_START_ADDRESS (GL(dl_ns)[LM_ID_BASE]._ns_loaded, entry);                        
  }    

省略していますが、ELF_DYNAMIC_RELOCATE()によってGOTの設定が行われているようです。

最後にあるreturn の値が
(ELF_MACHINE_START_ADDRESS これ)
main()の方の_startのアドレスに相当しているようですね。
戻り値が%eaxに入るので、それを%ediに転送しています。
その後%ediは一度も書き込まれていないので、最後の行のJmpでmain()の方の_startに飛ぶようです。

main()に来る前に呼ばれる関数の確認 (2/3)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/07/18 19:32

    _dl_runtime_resolveはカーネルではなくダイナミックリンカローダによってGOTに登録されていました。

    キャンセル

同じタグがついた質問を見る

  • C

    4528questions

    C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

  • コンパイラ

    37questions

    コンパイラは、プログラミング言語で記述したソースコードを、コンピュータの実行形式であるオブジェクトコードに変換するプログラムです。