オペレーティングシステムでの物理/論理/仮想アドレスという用語について少し混乱しています(Linux- open SUSEを使用しています)
ここに私が理解していることがあります:
物理アドレス-プロセッサがシステムモードの場合、プロセッサが使用するアドレスは物理アドレスです。
論理アドレス-プロセッサがユーザーモードの場合、使用されるアドレスは論理アドレスです。とにかく、これらは、オフセット値を持つベースレジスタを追加することにより、何らかの物理アドレスにマップされます。ある意味で、一種のメモリ保護を提供します。
仮想アドレスと論理アドレス/アドレス空間は同じであるという議論に出会いました。本当ですか?
どんな助けも大歓迎です。
私の答えは、最新のLinuxシステムで実行されているIntel CPUに当てはまります。私は、カーネルコードではなく、ユーザーレベルのプロセスについて話しています。それでも、他の可能性について考えるのに十分な洞察を与えると思います
質問3について:
仮想アドレスと論理アドレス/アドレス空間は同じであるという議論に出会いました。本当ですか?
私の知る限り、少なくともIntelプロセッサ上で動作する最新のOSでは、それらは同じです。
詳細を説明する前に、2つの概念を定義してみましょう。
仮想アドレスは、仮想アドレス、OS、およびMMU(メモリ管理ユニット)と呼ばれるハードウェア回路と一緒です。システムで単独で実行されているプログラムを除外し、アドレス全体を取得します。スペース(32ビットシステムを使用すると、プログラムは4 GBのRAMを持っていると見なされます。大まかに言えば)。
明らかに、一度に複数のプログラムを実行している場合(GUI、Initプロセス、シェル、時計アプリ、カレンダーなど何でも)、これは機能しません。
起こることは、OSがプログラムメモリの大部分をハードディスクに配置することです。最も使用する部分はRAMにありますが、そうではありません。知っている住所があります。
例:プロセスには、(counter)という名前の変数に仮想アドレス0xff(想像上...)が割り当てられ、別の変数(oftenNotUsed)に仮想アドレス(0xaa)が割り当てられている場合があります。
すべてのリンクが発生した後にコンパイルされたコードのアセンブリを読むと、それらのアドレスを使用してそれらにアクセスすることになりますが、(= Not = Used)変数は0xaaにRAM 、使用していないため、ハードディスクに保存されます。
さらに、変数(カウンター)はおそらく物理的に(0xff)にはならず、CPUが0xffにあるものを取得しようとするとRAMのどこかになります。MMUおよびOSの一部は、マッピングを行い、RAMで実際に使用可能な場所からその変数を取得します。0xffにないことに気付くことさえありません。
プログラムが(しばしばNotUsed)変数を要求するとどうなりますか? MMU + OSはこの「ミス」に気づき、ハードディスクからRAMにそれをフェッチし、アドレス(0xaa)にあるかのように引き渡します。このフェッチは、 RAMに存在していたいくつかのデータは、ハードディスクに送り返されます。
システムのすべてのプロセスでこれが実行されることを想像してください。誰もが4GBのRAMを持っていると思いますが、実際には誰も持っていませんが、プログラムの一部をRAMで物理的に利用できますが、ほとんどのプログラムはハードディスクにあります。 t HDに配置されるプログラムメモリのこの部分と、ファイル操作でアクセスできるプログラムデータを混同しないでください。
仮想アドレス:プログラムで使用するアドレス(CPUがデータを取得するために使用するアドレス)は実際のものではなく、MMUを介して何らかの物理アドレスに変換されます。誰でも持っており、そのサイズはシステムに依存します(32ビットを実行しているLinuxは4GBのアドレス空間を持っています)
物理アドレス:OS上で実行している場合に到達できないアドレス。仮想アドレスに関係なく、データがRAM内に存在する場所です。他のプロセスのためにより多くのスペースを収容するために、データがハードディスクに行き来する場合、これは変わります。
上記で説明したことはすべて、概念全体を簡略化したものですが、コンピューターシステムのメモリ管理部分と呼ばれるものです。
物理アドレス-プロセッサがシステムモードの場合、プロセッサが使用するアドレスは物理アドレスです。
必ずしも真実ではありません。特定のCPUに依存します。 x86 CPUでは、ページ変換を有効にすると、すべてのコードは物理アドレスまたは物理アドレスに簡単に変換可能なアドレス(SMM、AFAIKを除くが、ここでは重要ではありません)で動作しなくなります。
論理アドレス-プロセッサがユーザーモードの場合、使用されるアドレスは論理アドレスです。これらは、オフセット値を持つベースレジスタを追加することにより、とにかく何らかの物理アドレスにマッピングされます。
論理アドレスは、必ずしもユーザーモードだけに適用されるわけではありません。 x86 CPUでは、カーネルモードにも存在します。
仮想アドレスと論理アドレス/アドレス空間は同じであるという議論に出会いました。本当ですか?
特定のCPUに依存します。 x86 CPUは、セグメントが明示的に使用されないように構成できます。これらは暗黙的に使用され、それらのベースは常に0です(スレッドローカルストレージセグメントを除く)。論理アドレスからセグメントセレクタをドロップすると、32ビット(または64ビット)仮想アドレスと値が一致する32ビット(または64ビット)オフセットが残ります。この単純化されたセットアップでは、2つが同じであるか、論理アドレスが存在しないと考えることができます。それは真実ではありませんが、最も実用的な目的のためには、十分な近似値です。
Intel x86 CPUの以下の回答ベースを参照しています
論理アドレスと仮想アドレスの違い
プログラムが実行されているときはいつでも、CPUは(16ビットセグメントセレクターおよび32ビットオフセット)を含む命令の論理アドレスを生成します。基本的に、仮想(線形アドレス)は論理アドレスフィールドを使用して生成されます。
セグメントセレクターは、最初の13ビットがインデックスである16ビットフィールドです(これは、セグメント記述子へのポインターはGDTにあります。以下で説明します)、1ビットTIフィールド(TI = 1、LDTを参照、TI = 0はGDTを参照)
セグメントセレクターORセグメント識別子はコードセグメントを指しますORデータセグメントORスタックセグメントなど。Linuxには1つのGDTが含まれます/ LDT(グローバル/ローカル記述子テーブル)各セグメントの8バイト記述子を含み、セグメントのベース(仮想)アドレスを保持します。
したがって、各論理アドレスに対して、以下の手順を使用して仮想アドレスが計算されます。
1)セグメントセレクタのTIフィールドを調べて、どのディスクリプタテーブルにセグメントディスクリプタが格納されているかを判断します。このフィールドは、記述子がGDT(セグメンテーションユニットがgdtrレジスタからGDTのベースリニアアドレスを取得する)またはアクティブLDT(この場合セグメンテーションユニットがそのベースリニアアドレスを取得する)のいずれかにあることを示しますldtrレジスタからのLDT)。
2)セグメントセレクタのインデックスフィールドからセグメント記述子のアドレスを計算します。インデックスフィールドに8(セグメント記述子のサイズ)が掛けられ、その結果がgdtrまたはldtrレジスタの内容に追加されます。
3)論理アドレスのオフセットをセグメント記述子のベースフィールドに追加し、線形(仮想)アドレスを取得します。
現在、仮想アドレスから物理アドレスを変換するのはページングユニットの仕事です。
参照:Linuxカーネルの理解、第2章メモリアドレス指定
通常、発行されるすべてのアドレス(x86アーキテクチャの場合)は、セグメントテーブルを介して線形アドレスに変換される論理アドレスです。リニアアドレスへの変換後、ページテーブルを介して物理アドレスに変換されます。
同じことを詳細に説明する素晴らしい記事:
http://duartes.org/gustavo/blog/post/memory-translation-and-segmentation/
ユーザーの仮想アドレスこれらは、ユーザースペースプログラムから見た通常のアドレスです。ユーザーアドレスの長さは、基盤となるハードウェアアーキテクチャに応じて32ビットまたは64ビットであり、各プロセスには独自の仮想アドレススペースがあります。
物理アドレスプロセッサとシステムのメモリ間で使用されるアドレス。物理アドレスは32ビットまたは64ビットの量です。状況によっては、32ビットシステムでも64ビットの物理アドレスを使用できます。
バスアドレス周辺バスとメモリ間で使用されるアドレス。多くの場合、プロセッサが使用する物理アドレスと同じですが、必ずしもそうとは限りません。もちろん、バスアドレスはアーキテクチャに大きく依存しています。
カーネル論理アドレスこれらはカーネルの通常のアドレス空間を構成します。これらのアドレスは、メインメモリのほとんどまたはすべてをマップし、多くの場合物理アドレスであるかのように扱われます。ほとんどのアーキテクチャでは、論理アドレスとそれに関連付けられた物理アドレスは、一定のオフセットだけが異なります。論理アドレスはハードウェアのネイティブポインターサイズを使用するため、32ビットシステムが非常に装備されている物理メモリのすべてをアドレス指定できない場合があります。論理アドレスは通常、unsigned long型またはvoid *型の変数に格納されます。 kmallocから返されるメモリには論理アドレスがあります。
カーネル仮想アドレスこれらは、物理アドレスへの直接マッピングを必ずしも持たないという点で、論理アドレスとは異なります。すべての論理アドレスはカーネル仮想アドレスです。 vmallocによって割り当てられたメモリにも仮想アドレスがあります(ただし、直接の物理マッピングはありません)。関数kmapは仮想アドレスを返します。通常、仮想アドレスはポインター変数に格納されます。
論理アドレスがある場合、マクロ__pa()(で定義)は、関連する物理アドレスを返します。物理アドレスは、__ va()を使用して論理アドレスにマップバックできますが、メモリが少ないページのみです。
参照 。
論理メモリは、それぞれのプログラムに対して相対的です(プログラムの開始点+オフセット)
仮想メモリは、RAMとディスクにマップするページテーブルを使用します。このようにして、各プロセスは、個々のプロセスごとにより多くのメモリを確保できます。
物理アドレスは、メモリユニットから見えるアドレス、つまりメモリアドレスレジスタにロードされるアドレスです。論理アドレスは、CPUによって生成されるアドレスです。ユーザープログラムは実際の物理アドレスを見ることができません。メモリマッピングユニットは論理アドレスを物理アドレスに変換します。ユーザープロセスによって生成された論理アドレスは、使用する前に物理メモリにマップする必要があります。
あなたが小さなプログラムを書くとき、例えば:
int a=10;
int main()
{
printf("%d",a);
}
compile: >gcc -c fname.c
>ls
fname.o //fname.o is generated
>readelf -a fname.o >readelf_obj.txt
/ readelfは、0と1になるオブジェクトファイルと実行ファイルを理解するコマンドです。出力はreadelf_onj.txtファイルに書き込まれます /
`>vim readelf_obj.txt`
/ *「セクションヘッダー」の下に、オブジェクトファイルの.data .text .rodataセクションが表示されます。すべての開始アドレスまたはベースアドレスは0000から開始され、「サイズ」という見出しの下のサイズに達するまでそれぞれのサイズに拡大します---->これらは論理アドレスです。* /
>gcc fname.c
>ls
a.out //your executabe
>readelf -a a.out>readelf_exe.txt
>vim readelf_exe.txt
/ *ここで、すべてのセクションのベースアドレスはゼロではありません。特定のアドレスから始まり、特定のアドレスに到達します。リンカは、すべてのセクションに連続したアドレスを提供します(readelf_exe.txtファイルで確認します。各セクションのベースアドレスとサイズを確認します。連続して開始します)。ベースアドレスのみが異なります。アドレス空間。* /
物理アドレス->メモリには物理アドレスがあります。実行可能ファイルがメモリにロードされると、物理アドレスが割り当てられます。実際には、仮想アドレスは実行のために物理アドレスにマップされます。
ユーザーモードまたはユーザースペースでは、プログラムから見えるすべてのアドレスは仮想アドレスです。カーネルモードの場合、カーネルから見たアドレスはまだ仮想ですが、物理+ pageoffsetに等しいため論理と呼ばれます。物理アドレスは、RAMによって見られるものです。仮想メモリでは、プログラム内のすべてのアドレスはページテーブルを通過します。