アカウント名:
パスワード:
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
日々是ハック也 -- あるハードコアバイナリアン
書込み禁止領域に書きたければ (スコア:1)
str[ 0 ] = 'x';
とか?
でも実際に動かしてみると、
Segmentation fault
だって。
アタクシだめぽ (スコア:1)
けど、とりあえず(ここ大事)ソースに書いてコンパイルしてみたところ
コンパイラさんは
警告: 代入が読み込み専用領域で行われました
で、実行させたら
セグメンテーション違反です
ですって。
マニヤックな解説 (スコア:2)
を
char *str = "afo";
としても結果は同じでした。
コンパイルで警告が出ないところは違いますが。
# コードとしてタチが悪いものの今回の現象が解りやすいのは後者かも知れない
で、この "afo" っていう文字列は「文字列定数」なのです。"afo"は"afo"として使わねばならず、"xfo"とは出来ません。もしそういう使い方をしたいなら、
static char const str[] = "afo";
char buff[ 4 ];
strncpy( buff, str, sizeof( buff ) );
buff[ 0 ] = 'x';
とします(書き換え可能な領域は別に用意する必要があり
Re:マニヤックな解説 (スコア:1)
s/よそのプロセス/アクセスに特権が要るリソース/てなもんでしょうか。
よそのプロセスはそもそも見えないし。
# マニヤックな記述で文字列定数使うなら*"" = 'x';とかですかね。
Re:マニヤックな解説 (スコア:1)
仰せのとおり、他プロセスのメモリは見えませんね。
メモリディスクリプタテーブルのエントリが異なるので。
# 8086→80286→80386の進化ではこのメモリディスクリプタテーブルの辺りが一番面白いと思います。
見えてない部分を (スコア:1)
買うという意図を達することができそうな気がするんですが
どうなんでしょう?
なんとなーくWebを眺めていたら、VxWorksさんがバージョンアップして
いままで苦手だったメモリプロテクションなどを手がけるようになった
みたいですね。セミナに行くとサンプルコードが貰えそうな勢いですが、
会社に転がっている各種の評価用OSで試すことが出来たら面白いかもねー、
なんて妄想中です。
日記に書いたように、スレッドを複数生成してお互いに書き込み合い
って思ったのですが、(弱々しく自信なさげな声で)スレッドってメモリ領域
共有だから、無茶書きするならプロセス越えてやればいいのかしら?
って思ってみたり。
> 8086→(略)→80386の進化ではこのメモリディスクリプタテーブルの辺りが一番面白い
・・・そ、そういうものなんですか?
見えてない部分を無理矢理書き込む (スコア:1)
それでもって、見えない部分に書くというのが、「他プロセスの持ち物だけど、自分から見えていないと思われる場所にあてずっぽうで書く」 というのであれば、絶対に無理です。
自分のプロセスのメモリ空間(論理アドレス)にマッピングされていない領域なので。
というわけで「メモリディスクリプタテーブル」が避けて通れなくなりました。
# さすがに、コレを直接見たりいじったりする用が無いので、正しく説明できるかどうか怪しいのですが…
# 間違ってたらバシバシ指摘してください>みなさま
大雑把に言って、どの論理アドレスに何があるか?という一覧(とその属性)が「メモリディスクリプタテーブル」です。
物理メモリだったり、スワップされたディスク領域だったり、オープン済みのファイルだったり…
# まぁx86アーキテクチャから言うと、物理メモリかそれ以外かはCPU側の区別で、それ以降はOS側の区別になるのですが
80286はどうだったか忘れましたが80386以降は「メモリディスクリプタテーブル」はプロセスごとに別のテーブルを持ちます。
8086だと、「セグメント:オフセット」であくまでも物理メモリのアドレスしか指し示せませんでしたが、 80286以降は「セレクタ:オフセット」でOSが管理しているリソース(物理メモリや、スワップ領域や、ファイルの内容)を指し示します。
「セレクタ」とは「メモリディスクリプタテーブル」(という配列の)、添え字です。
C言語風にいうと、8086でポインタでメモリをアクセスしていたのが、80286以降ではポインタのポインタでアクセスする、ということになります。
プロセスのメモリアクセスでは、最初に必ず「メモリディスクリプタテーブル」を参照するので、 物理メモリの中でも、アクセスすると具合の悪いことが起きそうなエリア(よそ様のプロセスのメモリなど)は、 「メモリディスクリプタテーブル」に書いておかなければ良いのです。
というわけで、どーやってもよそ様のプロセスの持ち物に手を出す事は出来ないのです。
# 「メモリディスクリプタテーブル」を書き換えればそれも可能ですが、ほぼ間違いなく特権が必要のハズです。
で、メモリプロテクションでオチるというのは何か?というと、 「メモリディスクリプタ」を参照した結果、物理メモリがある領域なら、(読み取り専用の所を書こうとしない限り)何の問題も無いのですが、 そうではない領域だと、OSに処理がゆだねられます。
# CPU的には物理メモリが無い場所へのアクセスとか言う無茶で手におえない要求を、OSに押し付けてしまうわけです。
OSは“どこのアドレスに何をしようとしたのか”を見て、正常な処理の場合であれば、どこかから空きメモリを探し出してきて割り付けて値を設定したり、 アクセスされた内容をディスクに書き戻したりしますが、OSにも覚えが無いようなアドレスだったりすると、プロセスにシグナルを送りつけるわけです。
んと、えと。 (スコア:1)
1.セグメント内空間
2.リニアアドレス
3.物理アドレス
みたいになってます。
# 286ではページングできないので2と3は一緒です。
セグメントは1-2間の変換に使います。なのでセレクタ:オフセットの組で指
定できるのは2のリニアアドレスです。
2-3の変換にはページテーブルを用います。具体的にはCR3でページテーブル
の集合であるページディレクトリの物理アドレスを指定してページテーブル群
を指定します。んで、このページテーブル群がプロセス空間になります。
# ページテーブルの指定はページディレクトリでページテーブルのリニアア
# ドレスを指定します。この辺は厄介でおもしろいところです。
プロセスを切り替える際にはページテーブル群をまるごと切り替えてしまうの
で、よそのプロセスの持ちものは文字どおり見えなくなります。もっとも、カ
ーネルから実メモリが全部見えるようにマッピングすることも多いのでカーネ
ルによっては絶対に見えないわけでもありません。が、そこは当然触るのには
特権が必要な領域なわけです。
で、IA32では、
a.セグメントの属性/特権
b.空ページ/特権
の2つの違反ができます。変な表現ですが。
*"" = 'x';みたいに文字列に書き込むというのはaに違反します。
*(int*)hoge = 0;はhogeの値によりますが、セグメント違反な場所ならa
セグメントがOKでページが割り当てられてないところならbの違反ができます。
ありがとうございます (スコア:1)
補足ありがとうございます。
80286と80386でアドレス変換の手順が一つ増えたハズだと思っていたのですが、それがページテーブルだったのですね...思い出してきました。
# 昔本を読んだ時にも、その辺りの関係がちっとも理解できず、苦労した記憶が…
# 「ディスクリプタ」とか「ディレクトリ」とか、ファイルシステムで同じ名前を持つ物と概念的な部分で混同してしまったり、
# アプリケーションで使っているアドレスを物理アドレスに変換してみようとした時に、今見ているテーブルが何のテーブルだか解らなくなったり…
昔はWin95でその辺りの物をいじったので、今度はLinuxで見てみることにします。
いやいや大した事は (スコア:1)