0

store_at(int)以下に示すように、渡された数値を指定された 16 進数の場所に格納する関数があるとします。

void store_at(int val)
{
int *ptr;
ptr = (int *)0x261;

// logic goes here

return;
}

指定された 16 進数の場所 (この場合は 0x261) に val を格納するロジックをどのように記述しますか?

言うことは通じます*ptr = val;か?これはCでは許可されていないことをどこかで読んだことを漠然と覚えています。

4

2 に答える 2

2

*ptr = val;動作します。ただし、このアドレスが割り当てられ、さらにアクセス可能であることを確認する必要があります。C で何をプログラミングしているのかわからなくても、アクセス許可のないアドレスへのアクセスを防止するいくつかの方法を提案できます。したがって、使用しているアーキテクチャや運用システムに大きく依存します。

たとえば、ATMEGA32 マイクロコントローラでは、そのためのメイン メモリへのアクセスに関する制限はありません。それから/のためにコードを読み、書き、実行することができます:

PORTB = 1;
// Knowing that PORTB is stored at 0x38, you can do the equivalent:
*((unsigned int *)0x0038) = 1;

しかし、それは組み込みシステム上です。メモリ空間への完全なアクセスが必要な場合 (アプリケーション サンドボックス内にある限り)、VirtualProtectWindows とmprotectLinuxで使用できます。

int val = 123;
DWORD oldprotection;

VirtualProtect((LPVOID)0x261, sizeof(int), PAGE_EXECUTE_READWRITE, &oldprotection);

*(int *)0x261 = val;

そして、これで使用できる保護の種類は次のとおりです:メモリ保護定数

そしてmprotect例:

int val = 123;

mprotect((const void *)(((int)(0x261) / PAGESIZE) * PAGESIZE), sizeof(int), PROT_WRITE | PROT_READ | PROT_EXEC);

*(int *)0x261 = val;

このmprotect例はテストされていないことに注意してください。保護などのためにサイズを大きくする必要がある場合があります。

そこによる除算PAGESIZEは、アドレスを正しく整列させるための単なるトリックです。また、アドレスが Linux では無効であることに注意してください。これは、 がそれより大きい場合、除算が 0 になるためです ( 「it will be」とPAGESIZE同じ)。


ポインターを使用してアドレスにアクセスするための構文によれば、これらはすべて機能します。

*(int *)0x261 = val;

int *ptr = (int *)0x261;
*ptr = val;
于 2012-10-09T20:25:55.507 に答える
0

はい、式*ptr = val(およびそれ以上*(int *)0x261 = val;) は C で完全に有効です。しかし、ランタイム環境の技術的な制限に直面しています。

最近のオペレーティング システムは通常、仮想メモリのサンドボックスでプロセスを実行します (そのため、プロセスは他のプロセスのメモリにアクセスして台無しにすることはできません)。技術的には、プロセスの仮想メモリは、読み取り専用でアクセスできる一連の領域のように見えます。 、ここからのコードの実行を許可しないものもあります。利用できない VM 領域にアクセスしようとするとSIGSEGV、Unix のようなシステムで発生するかAccess Violation、Windows システムでエラーが発生します。これは、読み取り専用メモリ領域に書き込み、オペレーティング システムによって禁止されている領域でコードを実行しようとする場合と同じです。 (たとえば、 pid で Linux プロセスの仮想メモリ マッピングを確認できます/proc/$PID/maps

プロセスのメモリは通常、オペレーティング システムによって管理されます (OS が提供する , などの関数を使用してヒープから新しいメモリを取得しますmalloc()calloc()スタック メモリ領域は、プロセスの起動時に OS によって割り当てられます)。リテラルポインタでデータを参照する必要があります。

もう 1 つの考えられる環境は、カーネル空間またはベアメタル C プログラムです。ここでは、すべての物理メモリを利用できますが、アクセスする対象を認識しておく必要があります (ポート、物理メモリのギャップ、またはハードウェアなどによって予約されます)。このような環境のプログラミングは高度なトピックであり、十分な C の経験が必要です。

于 2012-10-09T19:52:14.897 に答える