トップページ⇒tech
292コメント106KB

Linker && Loader

■ このスレッドは過去ログ倉庫に格納されています
0001さとし ◆k4PcAe16 NGNG
読んでる人いますか?
難しいような気がするんですが。。。
僕もリンカとローダを作れるようになれますか?
0140592 ◆m/EAH1Sb4Q NGNG
>>139
>FORTRANのCOMMONは知っていますか?
>これが現在最大派閥のオーバーレイじゃないかな。
残念ながら、自分はFORTRANは使用したことがありません。

>それから大学の図書館で外部の人を入れないところなんてほとんどないよ。
>大学の目的に反しているからね。身分証明書があればほとんどOK。
>貸し出しはしてくれなくても有料コピーサービスは受けられる。
>OPACで在庫図書を検索できるし。
>気をつけるのは、学科の図書室は入れないことが多いこと。
わざわざ、知らせてくれてすいません。
そこ大学の学生でなければ見れないと思ってました。
後で気づいたんですけど国会図書館を使うっていう手段もあるなと思いました。

現在は、10章「動的なリンクとロード」を読み終えて、11章へ突入。
10章は、中々面白かったです。一番身近な感覚で勉強できますからね。

今日中に終わるか!?
0141592 ◆m/EAH1Sb4Q NGNG
終わったー!!

最後は、Javaでした。ちょこっとしかなかったけど無いよりましか。
全てをざっと読んだ感想は、やはり一筋縄にはいかないものだと思った。
Linker、Loaderを詳細に分かりたい人はこの本だけでなく、
その他の書籍、Web、ソース参照等でカバーしなくてはいけないと思う。

自分もこれからいろいろと調べなくてはならないことが山程あるなと感じた。
0142デフォルトの名無しさんNGNG
LinuxのELFにおいて、シェアードライブラリにスタティックライブラリ
をリンクする事は出来ないのでしょうか?

新規作成分のa.o b.o c.o と既存の流用可能な hoge.a があった
時に、a.o, b.o, c.o, hoge.a から libHoge.so を作りたいのですが、
どうしても hoge.a をリンクしても libHoge.soにシンボルがリンク
されません。

0143デフォルトの名無しさんNGNG
*.soは、load時にrelocationできるようになっている。
*.aはそうなっていないので、*.soに取り込むことはできない。
arで*.oにばらしてもダメ。

外部シンボルへの参照方法が根本的に違う。
0144デフォルトの名無しさんNGNG
>>143
それはつまり、再配置可能な形態(EXE,DLL)と
オブジェクトファイルの違いということですか?
*.aというのは用はオブジェクトファイルの集合体ですよね。

オブジェクトファイル内のアドレス値は、ファイルイメージ内の
相対アドレスすら決定されていない(リンク時にそれは決定される)から。
逆に(EXE,DLL)は、ローダによって実行時に、各セクションごとメモリ上に
割り当てられるとしても、それはオブジェクトファイル形式にのっとった
操作だから、先頭から何バイト目かは分る。つまり相対アドレスが
決定できる。EXEはプロセス中に一つしか有り得ないから、
DLLとはまた少し事情が違うのかな。
0145デフォルトの名無しさんNGNG
>>143
Linux って *.a から *.so つくるよね?

ld -shared --whole-archive とかって...
0146デフォルトの名無しさんNGNG
>>145
gccの-fpicを調べてください。
>>143の最後の一行の意味がわかるかと。
0147145NGNG
>>146
んー、私が知りたいのは

>143 で
「*.aはそうなっていないので、*.soに取り込むことはできない。arで*.oにばらしてもダメ。」

って言ってるけど、-fpic とか -fPIC でコンパイルしててもダメ(ar で *.o にバラしてもダメ)なの?

なんか -fpic とか -fPIC つきでコンパイルしてたら、ar で *.o にバラしてそれから *.so に取り込めそうだけど...
0148デフォルトの名無しさんNGNG
-fpic付きなら問題ない。

ただ、普通は.aだけ作る場合に-fpic付けることはまず無い。
0149145NGNG
>>148
了解。
確かに *.a だけなら効率のこともあるし -fpic 付けないね。
0150デフォルトの名無しさんNGNG
あー、unixって静的共有ライブラリなんてのがあるのか。納得。
0151デフォルトの名無しさんNGNG
prelinkってどうなの?
0152デフォルトの名無しさんNGNG
prelink
http://lss.eternity.ne.jp/cgi-bin/link/lss_frame.cgi?soft_add.cgi?5065
0153デフォルトの名無しさんNGNG
Mac OS Xだとupdate_prebinding/redo_prebinding
0154デフォルトの名無しさんNGNG
初歩的質問ですみません。
-lhoge とやった際、そのパスに、libhoge.a と libhoge.so の両方が
あった場合、どちらがリンクされるんでしょうか?
またlibhoge.aがリンクされる場合は、静的ライブラリの動的リンクって
事になるんでしょうか?
0155デフォルトの名無しさんNGNG
http://www.iecc.com/linker/
0156デフォルトの名無しさんNGNG
arにすると再配置情報が失われでもすんの?
コードがPICでなくともTEXTRELを処理すれば普通に動きそうだけど。
0157デフォルトの名無しさんNGNG
arじゃなくて*.aだった・・・
0158デフォルトの名無しさんNGNG
再配置情報って実際には何?
0159デフォルトの名無しさんNGNG
シンボルの相対位置情報と、
ディスパッチテーブル。
0160デフォルトの名無しさんNGNG
>>156
書き換えたらプロセス間で共有出来なくなるが。

そういやWinのDLLって再配置できるけど、あれってメモリ上では共有されないの?
0161デフォルトの名無しさんNGNG
再配置可能コード、リテラル等、どこに置こうが共有できるがある。
0162デフォルトの名無しさんNGNG
再配置が問題になるシンボルって、そのモジュールで
エクスポートする関数やグローバル変数なんじゃなくて、
モジュール内で参照してる、外部シンボルのことなんだよね?
実際、-fPICや-sharedつけても、外部シンボルを一切参照しない
コードなら、readelf -a foo.oの結果が全く同じだし。
0163デフォルトの名無しさんNGNG
外部シンボルでなくて、
内部のみ有効なシンボルであっても絶対番地参照してはならない。
そうして初めて外部シンボルだけ問題なモジュールとなる。
0164デフォルトの名無しさんNGNG
>>163
オオボケかましてました。自動変数だけのプログラム書いてました(汗
モジュールローカルなstatic変数とそれを用いるプログラム(宣言だけでは
もちろんダメ)を書いたら、-fPICの有無で、ちゃんとreadelf -aにおいて
異なる結果が得られました。何が違うのかはこれからよく見てみますが。
0165164NGNG
$ cat foo.c
static int abc=2;
int foo(void){int i=abc;}
$gcc -c foo.c;readelf -a foo.o > nopic.txt;gcc -c foo.c -fPIC;readelf -a foo.o > pic.txt
$diff nopic.txt pic.txt

いろいろあるけどとりあえず、セクションごとのサイズに注目すると、
< [ 1] .text PROGBITS 00000000 000034 000010 00 AX 0 0 4
< [ 2] .rel.text REL 00000000 0002b0 000008 08 7 1 4

< [ 7] .symtab SYMTAB 00000000 000200 000090 10 8 8 4
< [ 8] .strtab STRTAB 00000000 000290 00001e 00 0 0 1
----
> [ 1] .text PROGBITS 00000000 000034 000024 00 AX 0 0 4
> [ 2] .rel.text REL 00000000 0002e8 000010 08 7 1 4

> [ 7] .symtab SYMTAB 00000000 000214 0000a0 10 8 8 4
> [ 8] .strtab STRTAB 00000000 0002b4 000034 00 0 0 1

この辺りかな。
・.rel.textのエントリが1 -> 2、.symtabが9 -> 10になってる。
・エントリのサイズは.rel.textが8バイト、.symtab16バイト。
・それぞれ、_GLOBAL_OFFSET_TABLE_という名前のエントリが増えてる。

ってな感じですかね。
0166デフォルトの名無しさんNGNG
>>160
> 書き換えたらプロセス間で共有出来なくなるが。
勿論そうだけど、動くには動くでしょ。
PICでない*.aを*.soに取り込めないのは不思議。

>>165
shared objectは利用するプロセス毎に違うアドレスへ配置され得る。
だからコード中で直接絶対番地指定するとその部分を再配置しない限り
正常に動作してくれない。
で、再配置(=ここでは読み取り専用領域の書き換え)をしてしまうと>>160にある通り
メモリの共有が出来なくなって、プロセス毎にコピーを持つ必要が出来る。

PICなコードでは絶対番地指定が必要な時に
Global Offset Table(GOT)を通して間接的にアクセスする。
これだと読み取り専用領域を書き換える必要が無くなるので、
異なるプロセス間でその領域を共有出来るようになる。
i386ではGOTの参照に_GLOBAL_OFFSET_TABLE_という名前を使う事が出来る。

因みにdynamic linkerを通して関数を呼び出す時は
Procedure Linkage Table(PLT)ってのが使われる。
i386ではPLTはGOTを参照する変則的なジャンプテーブル。
link editorは外部関数等の呼び出しをPLTの該当エントリの呼び出しに
置き換え、実行時にPLTのコードはGOTを通してdynamic linkerの
シンボル解決ルーチンへジャンプする。
0167デフォルトの名無しさんNGNG
ついでに言うと、i386のPLTの各エントリは最初
1.GOT経由で2.へジャンプするコード
2.dynamic linkerへジャンプするコード
に分かれている。
dynamic linkerは2.から処理を受け取った時に1.で参照した
GOTのエントリを与えられるので、それを書き換える事により
2度目以降の同じ関数の呼び出しはdynamic linkerを通さずに
1.から直接ジャンプする事が出来る。
0168デフォルトの名無しさんNGNG
>勿論そうだけど、動くには動くでしょ。
>PICでない*.aを*.soに取り込めないのは不思議。

これは、オブジェクトファイルのTYPE=PROGBITSの
.textと.dataセクション、TYPE=RELの.rel.textや.rel.dataを
ちょこっと書き換えればPIC形式のオブジェクトファイルに
変換できるだろう、という意味ですか?
0169デフォルトの名無しさんNGNG
>>168
変換しない。
PICがPosition Independent Codeの略なのはオッケー?
コードをPICにする必要があるのは読み取り専用の領域を
プロセス間で使い回す為に再配置を避けたいから。
非PICな(直接絶対番地指定する)コードであっても、
dynamic linkerが読み取り専用領域を一旦書き込み可能にして再配置すれば
プロセス間でメモリ領域の共有が出来ないだけで動作はする筈。

「セクション」って事はlink editorの仕事について言ってるんだろうけど、
link editorはコードが読み取り専用領域のデータの再配置を必要とする場合に
DT_TEXTRELなりDF_TEXTRELなりの情報を載せてdynamic linkerが
正しく処理出来るようにすれば良いんじゃないかな。
0170デフォルトの名無しさんNGNG
>>169
>変換しない。
そうはいっても>>165の簡単なCのコードですら、アセンブラにした段階で
.textセクションに異なるコードを生成してますよ。

NON-PIC
foo:
subl $4, %esp
movl abc, %eax
movl %eax, (%esp)
addl $4, %esp
ret
.size foo, .-foo
PIC
foo:
subl $4, %esp
call __i686.get_pc_thunk.cx
addl $_GLOBAL_OFFSET_TABLE_, %ecx
movl abc@GOTOFF(%ecx), %eax
movl %eax, (%esp)
addl $4, %esp
ret
.size foo, .-foo
.section .gnu.linkonce.t.__i686.get_pc_thunk.cx,"ax",@progbits
.globl __i686.get_pc_thunk.cx
.hidden __i686.get_pc_thunk.cx
.type __i686.get_pc_thunk.cx, @function
__i686.get_pc_thunk.cx:
movl (%esp), %ecx
ret
0171デフォルトの名無しさんNGNG
>>170
それで何が問題だと思うの?
0172デフォルトの名無しさんNGNG
>>171
アセンブラソースをはりましたが、PICは>>167に書かれている通り、
GOT経由でモジュールローカルな変数(ここではabc)にアクセスしてますよね。
もし仮にNON-PICなモジュールをPICなモジュールとして使おうとすれば、
そのようなGOTへのアクセスルーチンを埋め込み、.rel.textセクションにGOTの
エントリを追加しなくてはならないように思います。
0173デフォルトの名無しさんNGNG
>>172
非PICなコードに必要なのは
movl abc, %eax
のabcの再配置であって、GOT経由のアクセスにする事ではないんじゃ。
0174デフォルトの名無しさんNGNG
>>173
>非PICなコードに必要なのは
>のabcの再配置であって

非PICコードからEXEを作るなら、static変数の
アドレスはリンク時に確定すると思うけど。
.rel.textセクションにエントリが追加されてるのは、
リンク時に.textセクション内のアドレス解決を行うものの
一覧だと思うし。
0175デフォルトの名無しさんNGNG
>>174
EXEではそう。
0176デフォルトの名無しさんNGNG
話がかみあっていないような気がしますが…

>>174
実行するアドレスが一意に決まるなら、それでも問題はないですな。
つーかstaticに限らず全てのアドレス参照がリンク時に解決できなきゃいけない。
あと.rel.textはアドレス解決には関係ない。

例外としてDOSみたいに実行時にアドレスが決定される場合は、ロードした時に
ごにょごにょやるしか無いけど。
今時そんなOSはまずないが。
0177デフォルトの名無しさんNGNG
>あと.rel.textはアドレス解決には関係ない。

.rel.textセクションというのは、.textセクション内の
コード中における、アドレス値の一覧なのではないでしょうか。
各エントリは.textセクション内のオフセットを示していると思いますがいかがでしょうか。

下は>>167のコードを-fPICをつけてコンパイルしたものの.rel.textセクションです。
Relocation section '.rel.text' at offset 0x3c8 contains 3 entries:
Offset Info Type Sym.Value Sym. Name
00000004 00000a02 R_386_PC32 00000000 __i686.get_pc_thunk.cx
0000000a 00000b0a R_386_GOTPC 00000000 _GLOBAL_OFFSET_TABLE_
00000010 00000309 R_386_GOTOFF 00000000 .data
↑ここのOffsetとは.textセクションの先頭からのバイト数だと思います。

.rel.textを含む、TYPE=RELであるセクションに登録されている各エントリのデータ構造
/* Relocation table entry without addend (in section of type SHT_REL). */
typedef struct
{
Elf32_Addr r_offset; /* Address */
Elf32_Word r_info; /* Relocation type and symbol index */
} Elf32_Rel;

/* i386 relocs. */ 各エントリのタイプ一覧の抜粋 Elf32_Rel.r_infoの値
#define R_386_PC32 2 /* PC relative 32 bit */
#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */

コードはLINUX GLIBC-2.3.3のelf.hを参考にしました。他のOSだと型名などが
微妙に違うと思います。
0178デフォルトの名無しさんNGNG
$objdump -d foo.o から抜粋
00000000 <foo>:
0:83 ec 04 sub $0x4,%esp
3:e8 (fc ff ff ff) call 4 <foo+0x4> ;;__i686.get_pc_thunk.cx
8:81 c1 (02 00 00 00) add $0x2,%exc ;;_GLOBAL_OFFSET_TABLE_
e:8b 81 (00 00 00 00) mov 0x0(%ecx),%eax ;;.data
14:89 04 24 mov %eax,(%esp,1)
17:83 c4 04 add $0x4,%esp
1a:c3 ret

00000000 <__i686.get_pc_thunk.cx>:
0:8b 0c 24 mov (%esp,1),%ecx
3:c3 ret

$gcc -fPIC -shared -fomit-frame-pointer -o foo.so foo.c
$objdump -d foo.so から抜粋
00000648 <foo>:
648: 83 ec 04 sub $0x4,%esp
64b: e8 (13 00 00 00) call 663 <__i686.get_pc_thunk.cx>
650: 81 c1 (50 11 00 00) add $0x1150,%ecx ;;GOTのアドレスを%ecxに設定
656: 8b 81 (28 ff ff ff) mov 0xffffff28(%ecx),%eax ;;%eaxにabcの値をコピー
65c: 89 04 24 mov %eax,(%esp,1)
65f: 83 c4 04 add $0x4,%esp
662: c3 ret

00000663 <__i686.get_pc_thunk.cx>:
663: 8b 0c 24 mov (%esp,1),%ecx
666: c3 ret
0179デフォルトの名無しさんNGNG
>>177
型名とマクロはELFの本家ドキュメントのと同じで、
i386なら*BSDでも同じ名前を使ってます。
これ以上何と説明すれば良いやら分からないので、
ゼヒとも仕様を読んでくらはい……。

ELFにはrelocatableとexecutable、sharedの三形式があり、
再配置はlink editorとdynamic linkerの両方が扱うもので
それぞれの意味が違うってのは大丈夫ですよね?
>>169に書いた通り、>>173の再配置というのは
dynamic linkerが行う再配置の事を言っています。
0180デフォルトの名無しさんNGNG
>>179
>型名とマクロはELFの本家ドキュメントのと同じで、
>i386なら*BSDでも同じ名前を使ってます。

そうでしょうか。私はNetBSDとLinuxを使っていますが、
Elf32_Symに関しては、NetBSDは本家のドキュメントと異なっているように見えます。
ざっと見た印象により、上には書いただけですし、
ちょこっと調べた結果判明したのはここだけだったのでなんとも言えませんが。

CVS-HEAD
/usr/src/sys/sys/exec_elf.h
typedef struct {
Elf32_Wordst_name;/* Symbol name (.symtab index) */
Elf32_Wordst_value;/* value of symbol */
Elf32_Wordst_size;/* size of symbol */
Elf_Bytest_info;/* type / binding attrs */
Elf_Bytest_other;/* unused */
Elf32_Halfst_shndx;/* section index of symbol */
} Elf32_Sym;

GLIBC-2.3.3はこうです。
typedef struct
{
Elf32_Wordst_name;/* Symbol name (string tbl index) */
Elf32_Addrst_value;/* Symbol value */
Elf32_Wordst_size;/* Symbol size */
unsigned charst_info;/* Symbol type and binding */
unsigned charst_other;/* Symbol visibility */
Elf32_Sectionst_shndx;/* Section index */
} Elf32_Sym;
0181デフォルトの名無しさんNGNG
おっとtabがすっとんでしまいました。
CVS-HEAD
/usr/src/sys/sys/exec_elf.h
typedef struct {
Elf32_Word st_name; /* Symbol name (.symtab index) */
Elf32_Word st_value; /* value of symbol */
Elf32_Word st_size; /* size of symbol */
Elf_Byte st_info; /* type / binding attrs */
Elf_Byte st_other; /* unused */
Elf32_Half st_shndx; /* section index of symbol */
} Elf32_Sym;
GLIBC-2.3.3
typedef struct
{
Elf32_Word st_name; /* Symbol name (string tbl index) */
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;

あと
>再配置はlink editorとdynamic linkerの両方が扱うもので
>それぞれの意味が違うってのは大丈夫ですよね?
それはいいのですが、

>あと.rel.textはアドレス解決には関係ない。
リンク時において、.rel.textの情報を元に.textセクションのアドレス値を
決定してるように見えますが、これは「アドレス解決」とは呼ばないんですか?
リンク時にGOTへのオフセットを計算してますけど。
0182デフォルトの名無しさんNGNG
>>180
そう言えばElf_Byteとかやってたな……。
いい加減な発言をしてもうしわけない。

>>181
>> 再配置はlink editorとdynamic linkerの両方が扱うもので
>> それぞれの意味が違うってのは大丈夫ですよね?
> それはいいのですが
じゃあ何が通じてないんだろう……。

>> あと.rel.textはアドレス解決には関係ない。
これは自分の発言ではないのでなんとも。
dynamic linkerのレベルでは関係ありません。

link editorがnon-PICなrelocatableからsharedを作る話ですよね?
dynamic linkerがDT_RELやDT_RELAを元に見つけるrelocation tableへ
>>170の例で言うabc用のエントリを作ってDT_TEXTRELを彫り込む、
ってので何が問題だと思います?
0183162NGNG
誰が誰だか分り難いので番号入れます。

>>182
>じゃあ何が通じてないんだろう……。
えーと、私もこの前からELFについて勉強し始めたばかりで、
ローダーがどうELFを処理するのかについては、何も知らず、
このスレでも一切触れていません。EXE、DYNともにコンパイル時、
リンク時にどういった処理により作成されるかを、一つ一つ見ているわけです。

>link editorがnon-PICなrelocatableからsharedを作る話ですよね?
私はこの話に関しては何も言ってません。
>>169の「変換しない。」という一言がちょっと気になっただけです。

>>170を見ての通り、non-PICなオブジェクトファイルからDYNを作るとなると、
static変数をGOT経由で参照するようプログラムのロジックを書き変える必要が
あるだろうということ。EXEと違い、DYNにおいてはモジュールローカルな
static変数のアドレスが分らない点にあると思います。いつ、セグメント内のどこに
配置されるのか分らないですから。ローダーの動作を見てないので確かなことは
言えないですが、もし仮にローダーがプログラム内のstatic変数の{絶対、相対}アドレスを
計算してくれるなら、そもそもGOTは必要ないですよね?

GNUのツールはプリプロセッサ、コンパイル、アセンブル、リンクといったフェーズに
キッチリ分けることを重視しているように見えます。そこで疑問なのですが、コンパイル
フェーズで確定したプログラムロジックを後から修正するようなツールなどは
存在するのでしょうか?non-PICとはコンパイラによる最適化の一種だと私は
考えています。そして、non-PICオブジェクトファイルをDYNに含められないのは、
上に挙げたGNUツールの特徴のためだと考えてますがいかがでしょう。

ELFの扱いに関して、ディテールを含めた全体をキッチリ理解したいので、
私の勘違いによる批判、大いにWELCOMEです。
0184デフォルトの名無しさんNGNG
×そもそもGOTは必要ないですよね?
○static変数の参照においてはそもそもGOTは必要ないですよね?
0185156NGNG
>>183
> EXEと違い、DYNにおいてはモジュールローカルなstatic変数のアドレスが分らない
dynamic linkerは一意に決められますし、決められないと話になりません。

> もし仮にローダーがプログラム内のstatic変数の{絶対、相対}アドレスを
> 計算してくれるなら、そもそもGOTは必要ないですよね?
効率を無視すればこの状況では必要ありません。
i386でのGOTの使い道は>>166-167にある通りです。
dynamic linkerはsharedを配置するアドレスをプロセス毎に一意に決められますが、
普通は利用するプロセス毎に違うアドレスを使います。
>>170で言うabcのアドレスを特定のプロセスでの絶対番地に変換=再配置してしまうと、
同じコードを別のプロセスが利用する事が出来なくなります。
それでもプロセス毎にコードのコピーを持ってプロセス毎に再配置すれば、
メモリ領域が無駄になるだけで矛盾無く動作させる事は可能です。
コードを共有するのにはmmap()等を使います。

> コンパイルフェーズで確定したプログラムロジックを後から修正
abcの再配置情報をリンカが作成した上でDT_TEXTRELってフラグをsharedに付けるだけです。
PICに変換する必要は無いのでロジックはコンパイル以降変わりません。

>>184
> static変数の参照においてはそもそもGOTは必要ないですよね?
動けば良いという発想なら必要ありません。
0186162NGNG
>>185
>> EXEと違い、DYNにおいてはモジュールローカルなstatic変数のアドレスが分らない
>dynamic linkerは一意に決められますし、決められないと話になりません。
これはリンク時に限定した話です。

>dynamic linkerはsharedを配置するアドレスをプロセス毎に一意に決められますが、
>普通は利用するプロセス毎に違うアドレスを使います。
>>>170で言うabcのアドレスを特定のプロセスでの絶対番地に変換=再配置してしまうと、
>同じコードを別のプロセスが利用する事が出来なくなります。
・・・
>コードを共有するのにはmmap()等を使います。
おぼろげながらやっと理解できました。straceでローダーの動作を確認してみました。


そこでですが、やはり理解できないのは、
>> コンパイルフェーズで確定したプログラムロジックを後から修正
>abcの再配置情報をリンカが作成した上でDT_TEXTRELってフラグをsharedに付けるだけです。
>PICに変換する必要は無いのでロジックはコンパイル以降変わりません。
上で見た通り、dynamic linkerはメモリ上にプログラムコードを配置する時に
コードに埋め込まれたアドレス値を書き換えることは出来ないわけですよね?
0187162 186の続きNGNG
[[[ foo.o ]]]
00000000 <foo>:
0: 83 ec 04 sub $0x4,%esp
3: a1 (00 00 00 00) mov 0x0,%eax
8: 89 04 24 mov %eax,(%esp,1)
b: 83 c4 04 add $0x4,%esp
e: c3 ret

[[[ foo(EXE) ]]]
08048344 <foo>:
8048344: 83 ec 04 sub $0x4,%esp
8048347: a1 (98 94 04 08) mov 0x8049498,%eax
804834c: 89 04 24 mov %eax,(%esp,1)
804834f: 83 c4 04 add $0x4,%esp
8048352: c3 ret

foo.oからEXEを作る上では.rel.textに記載されているRelocation情報をもとに
カッコで囲まれたアドレスを「リンク時」決定することが出来ます。
0x8049498というのは、abcの絶対アドレスだと思われますが、これがリンク時に
確定できるのは、OSが何をどこに配置するのかを、処理系が分っているからですよね?
では、non-PICからDYNを作成するときには

3: a1 (00 00 00 00) mov 0x0,%eax

この一文のアドレス値には何を入れておけばいいのでしょうか?
dynamic linkerがDYNをロードするまではabcの絶対アドレスは確定しない。
dynamic linkerがアドレス値を確定しても、プログラム領域を書き変えるわけにはいかない。
0188156NGNG
>>186
> 上で見た通り、dynamic linkerはメモリ上にプログラムコードを配置する時に
> コードに埋め込まれたアドレス値を書き換えることは出来ないわけですよね?
いいえ、出来ます。
例えばmmap()ならMAP_PRIVATEでやってCoWによりプロセス毎にコピーを持つようになるだけです。
メモリの読み取り専用属性は変える必要がありますが。

>>187
> では、non-PICからDYNを作成するときには
>
> 3: a1 (00 00 00 00) mov 0x0,%eax
>
> この一文のアドレス値には何を入れておけばいいのでしょうか?
implicit addendです。
この場合はベースアドレスからのabcのオフセットでしょうね。
jumpのrelocationだと-4だと思います。
0189デフォルトの名無しさんNGNG
>>dynamic linkerはメモリ上にプログラムコードを配置する時に
>> コードに埋め込まれたアドレス値を書き換えることは出来ないわけですよね?
>いいえ、出来ます。
>例えばmmap()ならMAP_PRIVATEでやってCoWによりプロセス毎にコピーを持つようになるだけです。

open("/lib/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\220P\1"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1183432, ...}) = 0
mmap2(NULL, 1121740, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x40066000
mmap2(0x40172000, 16384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x10b) = 0x40172000
mmap2(0x40176000, 7628, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40176000
close(3) = 0

straceの出力をよく見れば、ld.soによる全てのmmap2(Linux)において
MAP_PRIVATE指定されていました。しかしO_RDONLYでopenして、PROT_READ|PROT_EXECという
保護属性の中で、MAP_PRIVATEというのはどんな意味があるのかな。。。

またMAP_DENYWRITEに関してはmanに以下のように書いてあるのに、ld-2.3.4.soにおいてもまだ
フラグ指定されてるのは、互換性だけの理由かな。
>このフラグは無視される。 (ずっと前は、マップ元のファイルへの書き込みを行おうとすると、
>エラー ETXTBUSY で失敗するようにシグナルが設定されていたが、これは denial-of-service
>(サービス拒否)攻撃の原因となった)


156さんの言ってることがmmapとCoWによりようやく理解できました。
non-PICをDYNに含めることにおいて「効率を〜」という話が出てくるのは
CoWを前提とした話だったのですね。なるほど。
それから考えるとたしかに、DYNにnon-PICを含むことが出来ないのは、
おかしな話に思えます。ELFの仕様が出来上がったのは10年も昔の話だし、
MMUのないCPUなどの事情も考慮されているのかもしれないですね。
他にはGNUツールの開発者のポリシー、またはセキュリティー的な事情とかも
ありうるのかな。ELFを理解できたら、そのうち調べてみたいです。
0190デフォルトの名無しさんNGNG
>>185にメモリが無駄になるって書いてあるじゃん。
ページごとにCopyが起きるからね。

実際、関数呼び出しがあるページがコピーされたら、
プログラムの領域はほぼ全部コピーされちゃうんじゃない?
0191162NGNG
>>190
>>>185にメモリが無駄になるって書いてあるじゃん。
それは分っています。ローダーがページ境界に収まるように
DYN内の.non-pic.text(仮)セクションをメモリ内にコピー&アドレス値を
上書きすることでは、それ程無駄になら気も。気のせいかな。。。
ただ、CoWとは言っても、実行が開始される前のdynamic linkerが
コード内のアドレス値を書き換える時点において、ページが割り当てられて
しまうんですね。当たり前ですが。そのコードが実行されるかどうかに関係なく。
最近のOSならばページフォルトを利用したVMMによるファイルの遅延ロードは
どれも実装されていると思いますので、下手したら、静的リンクよりも
効率の悪いものになるかも?!

>実際、関数呼び出しがあるページがコピーされたら、
>プログラムの領域はほぼ全部コピーされちゃうんじゃない?
これはどういう意味ですか?できればもう少し詳しくお願いします。
先にPICなセクションを再配置しておいてから、non-PICなセクションを
処理すれば、あまり問題がないような。
DYNにnon-PICなコードを含めるのならば、セクションを別にする必要が
あるだろうと思います。

不勉強なのに適当な印象の話ばかり書き込みました。しばらくELFと
dynamic linkerについて調べてきます。
0192156NGNG
>>189
ちょうどcygwinでi386のelfを吐けるクロスコンパイラをビルドしたところだったので
試しにやってみたらnon-PICなrelocatableからsharedを作れました。
# ていうか最初に試せ >俺
>>142の人がどういう手順と環境で出来なかったのか気になります……。
0193デフォルトの名無しさんNGNG
>>192
おお、それはGOODニュースですね!
で、できればリンカオプションを教えてください・・・orz
0194162NGNG
ああ、これでいいのか。
$gcc -c -fomit-frame-pointer -o foo.o
$ld -o foo.so -shared foo.o
$objdump -d foo.so
000002b8 <foo>:
2b8: 83 ec 04 sub $0x4,%esp
2bb: a1 c8 12 00 00 mov 0x12c8,%eax
2c0: 89 04 24 mov %eax,(%esp,1)
2c3: 83 c4 04 add $0x4,%esp
2c6: c3 ret

なんか今まであれこれ憶測並べてたのが恥かしくなってきた。
もう寝る。。
0195156NGNG
>>191
> DYNにnon-PICなコードを含めるのならば、セクションを別にする必要がある
まるっきり勘で言いますけど、普通別にしないような気がします。
まあ勘なんでなるたけ突っ込まないで下さい。
あと細かい点ですが、実行時の視点で見るのはセクションでなくセグメントです。
ELFの場合この用語は混同しない方が良いです。

>>194
すんません、普段ELFを作れる環境を使わなかったんで……。

Sunのサイトで公開されてるSolarisのマニュアルにリンカに関する物があって、
それにELFの仕様の邦訳っぽい物も含まれてます。
所々微妙な訳もありますけど、一応メンテナンスはされてるようなんで
英語がとっつき辛い場合はそれも参考にすると良いかもしれません。
0196デフォルトの名無しさんNGNG
保守
0197鬼塚先生NGNG
誰か呼んだか?
0198デフォルトの名無しさんNGNG
>>197
それはGTO。
0199デフォルトの名無しさんNGNG
cygwinのldでブートセクタを生成しようとしてるんですが

ld -T boot.ls -o boot boot.o
したら
ld: PE operations on non PE file.
というエラーになって生成できません。

AMD k6-2のLinuxではちゃんとブートセクタが生成されて動作できました。
Cygwin版特有のオプション等が必要なんでしょうか?
解決方法を教えて下さい。
よろしくお願いいたします。

boot.ls
-----------------
OUTPUT_FORMAT("binary");
MEMORY
{
body : org = 0, len = 510
sign : org = 510, len = 2
}
SECTIONS
{
.text : { *(.text) } > body/* executable code */
.rodata : { *(.rodata*) } > body/* constants */
.data : { *(.data) } > body/* initialized data */
.bss : { *(.bss) } > body/* uninitialized data */
.sign : { SHORT(0xAA55) } > sign/* boot signature */
}
0200デフォルトの名無しさんNGNG
>>199
boot.oはどうやって生成した?
0201199NGNG
>>200
Makefileの内容です。

all:
gcc -Os -c -o img/boot.o boot.s
ld -T img/boot.ls -o img/boot img/boot.o
gcc -Os -c -o img/kernel.o kernel.c
ld -T img/kernel.ls -o img/kernel img/kernel.o
dd if=img/my_default.img of=img/my.img 2> /dev/null
dd if=img/boot of=img/my.img conv=notrunc 2> /dev/null
dd if=img/kernel obs=512 seek=1 of=img/my.img
0202デフォルトの名無しさんNGNG
boot.oがELFか、リンカスクリプトがELF前提か
どっちかだと思ったんだよな。
ldのメッセージは前者っぽいんだけど
gccがcygwinネイティブなら後者かなー。
今携帯からなんでPEのリファレンスがねーのよ。
0203199NGNG
お忙しい中ありがとうございます。

ばいなりエディタでboot.oを各環境とも開いてみたらLinux側は先頭に
.ELF
があって、Cygwin側の先頭は
L<
text
って感じでした。
自分ではこれが何を意味しているか分からないですが参考までに。
よろしくお願いいたします。
0204デフォルトの名無しさんNGNG
えー、まだ出先でリファレンスがないので、予想だけ書いとくね
リンカスクリプトのboot.lsが元のオブジェクトファイルの中から
.textセクションとか.rodataセクションを抜きだして
(セクション構造のない)ベタなbinaryにしようとしてるわけだけど、
このセクション構造がELFにあってPEにないもので、
cygwinで作ったバイナリがPEなもんだから
ldが処理できませーんとかになってんじゃないのかなみたいな
0205デフォルトの名無しさんNGNG
ld -v -T img/boot.ls -o img/boot img/boot.o
して詳細メッセージ出したのをはってもらえない?
0206199NGNG
以下のようになりました

$ ld -v -T img/boot.ls -o img/boot img/boot.o
GNU ld version 2.15.91 20040725
ld: PE operations on non PE file.
0207199NGNG
試しにに-Vにしてみたら。

$ ld -V -T boot.ls -o img/boot boot.o
GNU ld version 2.15.91 20040725
Supported emulations:
i386pe
ld: PE operations on non PE file.

となりました。
0208デフォルトの名無しさんNGNG
http://my.execpc.com/~geezer/osd/exec/
http://my.execpc.com/~geezer/embed/bugs.htm#mingbug
0209デフォルトの名無しさんNGNG
自分のプログラムでexe作りたいんですが、
超簡単なmsvcrtの関数使うサンプルとかないですかね?

そういや市販コンパイラが作るDLL関数の呼び出しコードって
インポートテーブルから
call DWORD ptr[import_table_address]
のようなことしてるけど、別に
mov eax, procedure_addres
call eax
としてもいいよなあ。
なんで1段参照増やしてんの?
インポートテーブル分無駄じゃない?
0210デフォルトの名無しさんNGNG
あ、全部のRVA持つよかコスト安いのか。
なるほどねー。
0211デフォルトの名無しさんNGNG
PEフォーマットの.idataのインポートセクションについて質問です。
の各DLL関数名の前に付いている、
「ヒント」の値って、何を入れるんでしょうか?

意味がまるでわからないです。
0212デフォルトの名無しさんNGNG
適当でいいんじゃね?
どうせ名前で調べるし
0213デフォルトの名無しさんNGNG
おそらく、DLLに登録された関数の序数(.DEFで登録する番号?)だと思いますが、
こんなのどうやって知るのでしょうか。
参照するDLLを調べろということですかね。


どっかから入手したpecoff.docによると、

>6.4.3. Hint/Name Table

>Field Hint
>Description
> Index into the Export Name Pointer Table.
> A match is attempted first with this value. If it fails,
>a binary search is performed on the DLL's Export Name Pointer Table.

ということは、わかんなかったら0とかの適当な値でよいと言う事でしょうか。
試しに全部0にしてやったらうまくいきました。

このヒントは、パフォーマンス上の理由でしかないのでしょうか?
0214デフォルトの名無しさんNGNG
>>212
そうですね。
実験してとりあえず無視して問題なかったので、
しばらく放置プレイしときます。
0215デフォルトの名無しさんNGNG
それとも、Kernel32.dllとかの基本的なDLLについては、
リンカであらかじめ序数を控えておいた方が良いのかな。

DLLの関数を全部列挙するなんてAPIないですよね・・・。
objdump.exeで取ってくるしかない?
0216デフォルトの名無しさんNGNG
>>215
同じことだけど PE 解析ルーチンを書けばいい。
0217デフォルトの名無しさんNGNG
セクションの場所とか位置変えるの面倒っすね。
それとexe自体よりスタートアップ作るのが面倒すぎる。
Win32APIしか使わないなら話は簡単だけど、
Cランタイム使えないとあんま意味ないんだよなあ。
とりあえずmsvcrt.dllを安全に使えるレベルとか考えてたけど
無理な気がしてきた。
mingwやlccwin解析すりゃいいんだろうけどね。
すげー遠い。
素直に既成のリンカへ.obj渡す事考えた方が早いかも。
0218デフォルトの名無しさんNGNG
Interface 12月号から、「リンカを100%使いこなそう!」
という連載が始まったよ。

今回は13Pで、主に用語など基礎知識の説明でした。
次回はELF形式のお話みたいなんで期待。
0219デフォルトの名無しさんNGNG
>210
Interfaceのこの手の記事は使えそうで使えないからなあ。
ELF形式なんてGNU系の資料いっぱいあるからPEやって欲しいのだが。
PEやる予定あるのかな。
無かったら笑えるがな。
0220デフォルトの名無しさんNGNG
>>218
0221デフォルトの名無しさんNGNG
PE イラネ
0222デフォルトの名無しさん05/02/05 10:26:28
age
0223デフォルトの名無しさん05/02/06 03:09:02
libcに存在するシンボルを自分のプログラム内で定義して
実行ファイルを作成した場合、必ずどっちが優先されるとか
ってあるんでしょうか?
0224Rubyist!05/02/06 03:12:03
interpositioningでぐぐれ
0225デフォルトの名無しさん05/02/14 14:21:01
オタにはまぁ買っといても損はないって感じかな
内容上重複というか同じような事書いてる部分は多いかもしれないが
読んで楽しめるとは思う
ちなみにLinker"s"
sが付く、これ重要
どうでもいいが漏れの近くの書店ではHTMLの分類の所に
隣近所はHTMLとかホームページとか
田舎の書店のアルバイトじゃ分類タイトルみただけじゃそうなるだろうなぁ
0226デフォルトの名無しさん05/03/05 05:38:08
ぶっちゃけ、「Linkers & Loaders」のような本が少なすぎる。
0227デフォルトの名無しさん05/03/05 05:49:40
まぁ資料WEBにあるし、マイナーなの乗せてたりとか表っぽいところとか
オタ本の分類だろうし
少なすぎるというかそもそもたくさんある類いの本じゃないよね
022822605/03/05 06:05:41
オタ本って...確かにそうなんだけど。
もっと美しく言うと専門書籍って言わない?(萌え本みたいな印象もあるし)
022922605/03/05 06:21:23
つ〜か、あえてこういう分野において本を出版する事が、専門書の価値として生きるんだけどなぁ。
みんな(出版社とか)は、わかって無いよなぁ。チャンスなのに。
0230デフォルトの名無しさん05/03/05 06:42:57
>>228
萌え本ってなんですか?
0231デフォルトの名無しさん05/03/05 08:36:54
>>230
http://www.google.co.jp/search?hl=ja&q=%E8%90%8C%E3%81%88%E6%9C%AC&btnG=Google+%E6%A4%9C%E7%B4%A2&lr=lang_ja
0232デフォルトの名無しさん2005/05/26(木) 21:34:03
>>226
×ぶっちゃけ、「Linkers & Loaders」のような本が少なすぎる。
○ぶっちゃけ、「Linkers & Loaders」のような本を読む人が少なすぎる。
0233デフォルトの名無しさん2005/05/26(木) 22:02:20
リンカー&ローダーとかPICとか*.a *.soを詳細に解説した本って売ってない?
0234本田& ◆xOS3wf.pJg 2005/05/27(金) 01:11:58
>>219
PEフォーマットってCOFFフォーマットの別名だよ。
0235デフォルトの名無しさん2005/05/27(金) 19:17:49
>>233
L&LかInterfaceの連載くらいしか見たことない。

>>234
PEとCOFFは同一ではないから、別名というのは違う。
COFFを拡張したのがPE。
0236デフォルトの名無しさん2005/05/28(土) 22:18:45
COFFとPEは結構用語が変わってるから拡張というよりM$ローカライズな希ガス
0237デフォルトの名無しさん2005/06/25(土) 21:26:29
プログラムを書くとリンカーが勝手にリンクしているcrt0.oを解説したドキュメントってどこかに無いですか?
いったいこれは何なのか。
私の書いたmain以外のstartとかendとかいったシンボル名は何なのかと。
0238デフォルトの名無しさん2005/06/25(土) 23:22:56
>>237
ソース見たほうが早いよね
0239デフォルトの名無しさん2005/06/25(土) 23:50:58
>>238
ソースがあるといいね。
■ このスレッドは過去ログ倉庫に格納されています