2

次のような簡単なプログラムをコンパイルしました

int main()
{
    return 0; 
}

Clang を実行可能ファイルに使用otoolし、コンパイラによって生成されたロード コマンドを報告するように求めました。私が興味を持っているのは、特にファイル内のセグメントLC_SEGMENT_64を記述するものです。__TEXT私が得る説明はこれです:

$ otool -lV foo
foo:
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 72
  segname __PAGEZERO
   vmaddr 0x0000000000000000
   vmsize 0x0000000100000000
  fileoff 0
 filesize 0
  maxprot ---
 initprot ---
   nsects 0
    flags (none)
Load command 1
      cmd LC_SEGMENT_64
  cmdsize 312
  segname __TEXT
   vmaddr 0x0000000100000000
   vmsize 0x0000000000001000
  fileoff 0
 filesize 4096
  maxprot rwx
 initprot r-x
   nsects 3
    flags (none)
Section
  sectname __text
   segname __TEXT
      addr 0x0000000100000f90
      size 0x000000000000000f
    offset 3984
     align 2^4 (16)
    reloff 0
    nreloc 0
      type S_REGULAR
attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
 reserved1 0
 reserved2 0

私の質問はfileoff、2 番目のロード コマンドのフィールドがゼロに設定されているのはなぜですか?

このフィールドに関する Apple のドキュメントには、次のように記載されています。

ファイルは、fileoff からメモリ内のセグメントの先頭である vaddr にマップされます。

filesizeこれにより、最初は、このフィールドが と組み合わせて、ローダーに次のようなものを示していると信じるようfileofffileoff + filesizeなりました。しかし、もちろん、この値がゼロの場合、私の仮定は成立しません。

セグメントには少なくとも 1 つのセクションがあるため、ローダーはセクションの説明にあるそれぞれのオフセットの値を使用して実行するコードを特定するため、そのような値は必ずしも必要ではないと考えました。 、実際には、このセグメント内の最初のセクションにはoffsetフィールドの値があります (この場合は 3984 で、これは検証済みでotool -s __TEXT __text -j fooあり、ファイル内でこのセクションが配置されているオフセットを実際に参照しています)。

しかし、同じソース ファイル (つまり、 のMH_OBJECT代わりにtype を持つファイル) から生成されたオブジェクト ファイルに対して同じことを行うとMH_EXECUTE、得られる結果は次のようになります。

$ otool -lV foo.o
foo.o:
Load command 0
      cmd LC_SEGMENT_64
  cmdsize 312
  segname
   vmaddr 0x0000000000000000
   vmsize 0x0000000000000070
  fileoff 464
 filesize 112
  maxprot rwx
 initprot rwx
   nsects 3
    flags (none)
Section
  sectname __text
   segname __TEXT
      addr 0x0000000000000000
      size 0x000000000000000f
    offset 464
     align 2^4 (16)
    reloff 0
    nreloc 0
      type S_REGULAR
attributes PURE_INSTRUCTIONS SOME_INSTRUCTIONS
 reserved1 0
 reserved2 0

この場合、load コマンドのfileoffフィールドの値は、最初のセクションの値と同じ__textです。

4

1 に答える 1

1

otool を使用するとわかりにくくなりますが、答えは簡単です - ここで観察してください:

$ jtool -v -l /tmp/a | grep SEG
LC 00: LC_SEGMENT_64          Mem: 0x000000000-0x100000000  File: Not Mapped    ---/--__PAGEZERO
LC 01: LC_SEGMENT_64          Mem: 0x100000000-0x100001000  File: 0x0-0x1000    r-x/rw__TEXT
LC 02: LC_SEGMENT_64          Mem: 0x100001000-0x100002000  File: 0x1000-0x1098 r--/rw__LINKEDIT

__TEXT セグメントは、ファイル (またはファット (「ユニバーサル」) の場合はスライス) の先頭からマップされます。つまり、Mach-O ヘッダーを使用します。Mach-O は他のロード コマンド (特にライブラリ) のために dyld (使いやすいローダー) によって解析されるため、これは実際には機能です。もう 1 つの問題は、__TEXT.__text がまったく同じページにあることが多いため、ページ全体をマップする必要があることです。

于 2016-03-19T15:43:34.747 に答える