.#include<stdio.h>
int i = 9;
int main(){
....
と宣言した場合、int i はグローバル変数になると思います。
共有ライブラリのなどの外部関数を参照するのにGOTの存在が必要だと思っていたのですが、グローバル変数へのアクセスの際にもGOTを活用する場面が出てくるようです。
位置独立グローバル変数と非位置独立グローバル変数とは何が違うのですか?
上記のint i は非位置独立グローバル変数であっていますか?
逆に、位置独立グローバル変数はどのようにして宣言するのでしょうか?
なぜ、グローバル変数へのアクセスにGOTが必要になってくるのかわかりません。
そもそもGOTから外部の関数にアクセスする際にも「共有ライブラリの仮想メモリ空間」と「各プロセスの仮想メモリ空間」とはそれぞれ独立していて、別の仮想メモリ空間にアクセスできませんよね?
GOT内に存在する外部関数のポインタは、どうやって「別空間のアドレス」を参照しているのでしょうか?
本の中に、
位置独立ではないコードから「グローバル変数」や「非static関数」を使うと再配置が発生し、メモリが共有されなくなってしまう・・・
と書いてあったのですが、意味がよくわかりません。
非位置独立コードにおいて、
マップされているメモリの内容を変更してしまうと、なぜメモリの共有ができなくなってしまうのですか?
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
位置独立グローバル変数と非位置独立グローバル変数とは何が違うのですか?
この言葉は聞いたことありませんが、
ダイナミックリンカが、リンク後の機械語に対する再配置処理(具体的には、オペランドにグローバル変数のアドレスを埋め込む)をしなくてすむなら、位置独立といえるでしょう。つまり、グローバル変数が位置独立になるのではなく、グローバル変数にアクセスするコードが位置独立になるわけです。
上記のint i は非位置独立グローバル変数であっていますか?
いえ、ソースコードだけでは、位置独立かどうかはきまりません。その変数にアクセスするコードがすべて位置独立であれば、位置独立なグローバル変数だと言えると思います。
逆に、位置独立グローバル変数はどのようにして宣言するのでしょうか?
ダイナミックリンクすれば、位置独立になります。このとき、共有ライブラリのコードからグローバル変数を参照するのであれば、コンパイル時に -fPIC をつけて位置独立なコードを生成しておく必要があります。そうでなければ、リンクエラーになります。 -fPIC を指定すると、グローバル変数にGOT経由でアクセスするコードが生成されます。
なぜ、グローバル変数へのアクセスにGOTが必要になってくるのかわかりません。
メモリ共有や実行時性能などの観点から、ダイナミックリンカが実行時に機械語の再配置処理を行うことはできません。したがって、ダイナミックリンクされるコードはすべて位置独立である必要があります。グローバル変数へのアクセスを位置独立にするためにグローバル変数のアドレスを保持したテーブル GOT を用意し、ダイナミックリンカが実行時にそのテーブルを埋めます。
i というグローバル変数があれば、それを参照する共有ライブラリのGOTにそのアドレスを埋めます。この処理はロード時に一括して行われます。
そもそもGOTから外部の関数にアクセスする際にも「共有ライブラリの仮想メモリ空間」と「各プロセスの仮想メモリ空間」とはそれぞれ独立していて、別の仮想メモリ空間にアクセスできませんよね?
いえ、共有ライブラリは各プロセスの仮想メモリ空間にそれぞれロードされます。ですので、アクセスできます。
非位置独立コードにおいて、
マップされているメモリの内容を変更してしまうと、なぜメモリの共有ができなくなってしまうのですか?
ここが一番重要ですが、プロセスAとプロセスBに共有ライブラリXがロードされたとします。プロセスAとプロセスBの仮想メモリ空間は別ですが、Xのコードを保持するメモリの内容が全く同じ場合は、一つの物理メモリを共有します。ここで、共有の単位はページです。Linux であれば、4Kbytes です。4Kbytes ごとに区切ったときにプロセスAとプロセスBが同じ内容を持っているとそのページの内容(ここでは、Xのコードセグメント)を保持するための物理メモリをプロセス間で共有します。このとき、そのメモリのアドレス(Xのコードが配置されるアドレス)はプロセスAから見たときととプロセスBから見たときで異なっていてもかまいません。
(余談ですが、スタティックリンクでも同じプログラムを2つ動かすとその text セグメントは共有されます。これは、プロセス間で同じ内容を参照するからです)
つまり、ページの内容が全く同じでないと共有できないわけです。もし、コードがグローバル変数を参照するときに非位置独立なコードで参照しているとどうなるでしょう。ダイナミックリンカがコードを書き換えてグローバル変数のアドレスを埋め込むことになります。グローバル変数の割当アドレスはプロセスによって異なる場合があります。そうなると、プロセス間で内容が異なるのでもはや共有できなくなってしまうわけです。
ですから、位置独立なコードで共有ライブラリを生成することでどのアドレスに配置されても同じ内容のコードで実行できるようにするわけです。
投稿2016/11/04 12:59
総合スコア3401
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
正直、「GOT」ってなんですか?と思いましたが...
例えば、ソースファイル a.c の中で、
int i; main() { .... }
の様にiをグローバル変数として使っていて、ソースファイル b.c の中でも、
int i; func() { .... }
の様にグローバル変数 i を使っていて、
両方のファイルをリンクすると、変数 i が衝突しているので
リンクエラーとなってしまうかと思います。
しかし、 b.c の中で
extern int i; func() { .... }
と宣言し、最初に書いた a.c とリンクすると、b.c の中でも a.c の変数 i が参照できます。
つまり、同じ領域が割り当てられます。
またそれとは別に、 a.c の中で、
static int i; main() { .... }
として、 b.c の中で、
static int i; func() { .... }
とした場合は、a.c の i と b.c の i は別の変数となります。
つまり、別々の領域が確保されます。
ここでは、a.c と b.c の2個のファイルで書きましたが、
リンク対象がライブラリの場合でも同じです。
この様な事を知りたかったのでしょうか?
投稿2016/11/04 13:00
編集2016/11/04 13:01総合スコア241
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
初めに”GOT"って何?と思ってググってみた。
ld -z relro で GOT overwrite attack から身を守る
ここを読んで行ってようやく意味が分かった。
昔からリンカーが2パスでリンクをしてきたが、恐らく”OBJ”の時に中間的なアドレスを”仮”にセットして”EXE"や”DLL"などを作成するまでの間に攻撃を受ける危険についての解説であった。
きっと質問の意図は、最終的な実行形式が作成される場合、そのスタティックな位置(メモリー配置)が決まるまでGOTが要るが、何故?という質問と考えたのですが。
投稿2016/11/04 12:03
総合スコア3778
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。