何故 Windows API関数の序数がOSの版毎にバラバラでも、アプリケーションが正しく動くのか? – プログラミング – Home

何故 Windows API関数の序数...
 
通知
すべてクリア

何故 Windows API関数の序数がOSの版毎にバラバラでも、アプリケーションが正しく動くのか?


ぶた
 ぶた
(@ぶた)
ゲスト
結合: 12年前
投稿: 15
Topic starter  

タイトルの疑問を解消すべく下記の検証をしたのですが、行き詰ってしまった為 皆様の
知恵と経験をお借りしたく投稿させて頂きました。
情報( 例 これを調べろ・誤解している・検証方法が間違っている )をお持ちでしたら、
どうかお教え頂けないでしょうか。宜しくお願い致します。

【検証1】
例えば kernel32.dll に実装されている LoadLibraryA() を例に採る。
Visual Studioに付くdumpbin.exeを使い、OS毎に↓のコマンドで LoadLibraryA() の序数
を調べる。

dumpbin /exports kernel32.dll | grep LoadLibraryA ( grep は Cygwin 1.7.17 の物を
使用 )

すると、OSの版毎にバラバラな事が分かった↓

・WinXP SP3 32[bit] Pro. の system32 フォルダで実行
581

・Win7 SP1 64[bit] Pro. の system32・SysWOW64 フォルダで実行
830

・Win8 64[bit] Pro. の system32・SysWOW64 フォルダで実行
961

ある環境( 例 WinXP )で LoadLibraryA() を使うアプリをビルド( 勿論 左記APIは暗黙的
リンク )して動いた物が、序数の互換性がない他環境( 例 上記Win7 )で正しく動いた。
動くのは当然としても、序数が異なる為 疑問。

【検証2】
「.exe と .dll を作り動作確認後、.dll だけ更新し 再び動作確認する」方法(下記)で
調べた。
結果、エクスポート要素と序数の対応が 新旧dllの間で変わると、期待通り 正しく動か
なくなってしまう事が確認できた。

1) test.dll に a() b() というエクスポート関数を用意。
序数は __declspec(dllexport) で自動生成( 関数名の文字コード順に、1から振られ
る )した。
その結果 序数は、a() が 1、b() が 2 を振られた。

2) a() b() を順に呼ぶ test.exe を作り、↑ を暗黙的リンクし動作確認。予想通りに動
いた。

3) test.dll に _() というエクスポート関数を __declspec(dllexport) を伴って追加
し、dllのみビルドした。
その結果 序数は、_() が 1、a() が 2、b() が 3 を振られた。

4) ( ビルドせず )test.exe を実行すると、予想通り _() a() の順で呼ばれた。
DLL内の各関数の序数の振られ方が、 旧DLL 1) と 新DLL 3) の間で変わった( = 後方
互換性がなくなった )為。
それにより、ローダによって解決されるインポートアドレステーブルの各要素の結合
先が変わり、異なる関数が呼ばれた。

上記2つの検証結果が矛盾した所で、それ以上の調査で手詰まりになってしまった。


引用解決済
トピックタグ
AR2
 AR2
(@ar2)
Estimable Member
結合: 5年前
投稿: 110
 

 簡単な物言いになってしまいますが、自前で序数が管理できないものは序数など使わな
ければ良いだけです。
 Export時に名無しのAPIなら序数以外に指定方法がありませんが、「名前」さえ付けれ
ば序数が分からなくてもAPIのアドレスの取得が可能です。
 ですから、test.dllの各APIに名前をつけてあげてください。
 (プロジェクト構成が分かりませんが、多分「test.def」というファイルで定義される
べきと想像してます)

 取得方法を具体的に説明すると、GetProcAddress()を使って名前でアドレスを取得する
ようにすると序数に振り回されることはありません。
http://msdn.microsoft.com/ja-jp/library/cc429133.aspx


返信引用
AR2
 AR2
(@ar2)
Estimable Member
結合: 5年前
投稿: 110
 

 あと、「静的リンク」「動的リンク」という単語をキーワードに、DLLの使い方を学ば
れると良いかと思います。


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

関数のエクスポートには、
 1.名前でエクスポート。__declspec(dllexport) を使用
 2.序数のみでエクスポート。*.def に func @N して、NONAMEを指定
 3.両方できるようにエクスポート

がありますね。NONAMEを指定しない限り、
 4.名前で解決できる関数テーブルが作られる

わけですが、
 5.序数で解決できる関数テーブルも必ず作られる

わけです。NONAMEを指定すると名前で解決できる関数テーブルが
作成されないので、DLLのサイズが節約できます。
また、@Nを指定しないと、自動的に序数が割り当てられます。

さて、今日では一般に序数によるリンクはまったく行われません。
これは、名前による解決のほうが、融通が利くからですね。

当たり前ですが、名前による解決を行う場合は、
その関数に割り当てられている序数はまったく参照されません。


返信引用
YuO
 YuO
(@YuO)
ゲスト
結合: 22年前
投稿: 320
 

Export側だけでなく,実行ファイルのImportテーブルも見た方が良いですし,Dependency
Walkerで見た方がわかりやすいです。

ちなみに,【検証2】の通りにやっても,正しい関数が呼び出されます。
# 【検証2】に.DEFファイルでNONAMEを指定した,という記述がないので,__declspec
(dllexport)だけを使ってエクスポートしている
この場合,Dependency Walkerで実行ファイルを見ると,
・OrdinalはN/A
・Hintが0と1
・Functionがaとb
・Entry PointがNot Bound
という表示になります。
# dumpbin /importsで見ても,0と1の表示であることから,ordinalではなくhintが書かれ
ていることがわかる


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

ここの説明を信じてはいけません。

http://msdn.microsoft.com/ja-jp/library/253b8k2c(v=vs.80).aspx

•明示的リンクの場合、アプリケーションとインポート ライブラリをリンクする必要は
ありません。DLL 内の変更によってエクスポート序数が変更される場合、明示的リンク
を使うアプリケーションをリンクし直す必要はありません (序数値ではなく関数の名前
を使って GetProcAddress を呼び出すと仮定した場合)。他方、暗黙的リンクを使うアプ
リケーションは、新しいインポート ライブラリとリンクし直す必要があります。


返信引用
ITO
 ITO
(@ITO)
ゲスト
結合: 22年前
投稿: 1235
 

んー
 1.windowsのdllは序数値がOSバージョンによって変わっている。
 2.自前でEXEとDLLを作って試してみたけど、序数値が変わるとうまくいかない。
 3.windows APIは序数値が違うのになぜ上位互換性があるのだろう。
 4.動的リンクで使うLoadLibraryA()等の関数が入っているkernel32.dllでさえ
   序数値が違う。
どういう仕組みになっているのかわからなくなった。
ということみたいです。
僕としては推測ですが、
 kernel32.dllだけはそれぞれOS独自の暗黙的リンクにで関数が読み出されて後は動的
リンクで必要に応じて読み出される。だと思いますね。


返信引用
仲澤@失業者
(@uncle_kei)
Prominent Member
結合: 5年前
投稿: 828
 

exeが実行される順番は、

1.システムコールが実行されて、仮想アドレス空間が用意される(ntdll.dllかも)
2.exeの本体部分がマッピングされ、kernel32.dllがマッピングされ、
 プロセスが開始される。
3.exeの参照テーブルを見て、暗黙に参照されている全てのdllがマッピングされる。
4.exeのwmainCRTStartup()の実行->WinMain()の実行

という順番だと思います(vv;)。
従って、exeがなんかやり始めた時点では既に暗黙に参照されている全てのdllの
マッピングとダイナミックなリンクが完了しているわけですね。
現在ではLoad On Callはできないみたいですし。


返信引用
ロマ
 ロマ
(@ロマ)
ゲスト
結合: 18年前
投稿: 170
 

> ここの説明を信じてはいけません。
この書き方は変でした。
msdnの記述がおかしいということです。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました