14

アセンブリ言語では、次のような指示があります。

movl ax, [1000]

これにより、特定のメモリ位置にアクセスできます。

しかし、Cではこれに似たことができますか?

インラインアセンブリコードを使用asm()するとこれが可能になることはわかっていますが、これを実現するためのC固有の手法について知りたいと思います。

次のコードを試しましたが、セグメンテーションエラーが発生しました。

int *ptr=0xFE1DB124;
*ptr;

メモリの場所が以下のコードで識別されたため、これも混乱を招きました。

int var;
printf("\nThe Address is %x",&var);

したがって、メモリの場所は利用できますが、セグメンテーション違反が発生しています。

なんで?

4

4 に答える 4

10

一般的なCコンパイラを使用すると、整数からポインタを設定し、それを使用してメモリにアクセスでき、期待どおりの結果が得られます。ただし、これはC標準を超える拡張機能であるため、コンパイラのドキュメントをチェックして、それがサポートされていることを確認する必要があります。この機能は、特定のアドレスのメモリにアクセスする必要があるカーネルコードでは珍しく使用されません。通常、ユーザープログラムでは役に立ちません。

コメントで述べたように、発生している可能性のある問題の1つは、プログラムがロードされるたびに、オペレーティングシステムがプログラムをランダム化された場所にロードすることです。したがって、ある実行で検出したアドレスは、別の実行で使用されたアドレスにはなりません。また、ソースを変更して再コンパイルすると、異なるアドレスが生成される場合があります。

ポインタを使用して数値で指定されたアドレスにアクセスできることを示すために、アドレスを取得して、単一のプログラム実行内で使用できます。

#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>


int main(void)
{
    //  Create an int.
    int x = 0;

    //  Find its address.
    char buf[100];
    sprintf(buf, "%" PRIuPTR, (uintptr_t) &x);
    printf("The address of x is %s.\n", buf);

    //  Read the address.
    uintptr_t u;
    sscanf(buf, "%" SCNuPTR, &u);

    //  Convert the integer value to an address.
    int *p = (int *) u;

    //  Modify the int through the new pointer.
    *p = 123;

    //  Display the int.
    printf("x = %d\n", x);

    return 0;
}

明らかに、これは通常のプログラムでは役に立ちません。単なるデモンストレーションです。この種の動作は、特定のアドレスにアクセスする特別な必要がある場合にのみ使用します。

于 2013-03-26T13:55:07.750 に答える
6

ユーザースペースから特定のメモリにアクセスするには、 mmap()を使用してメモリアドレスをプログラム仮想アドレスにマップする必要があります。以下のCコードは実装を示しています。

「ABCDEFGHIJ」を含むファイル「test_file 」を取得します。

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>

int main(void)
{
    char *map_base_addr;  // Maping Base address for file
    int fd;         // File descriptor for open file
    int size = 10;

    fd= open("test_file", O_RDWR);  //open the file for reading and writing
    map_base_addr= mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);// Maping file into memory

    char *ch= map_base_addr;
    int i;

    /*Printing first 10 char*/
    for(i=0; i<size; i++)
            fputc(*(ch+i),stdout);
    printf("\n");

    *(ch+1) = 'b';
    *(ch+4) = 'z';
    *(ch+7) = 'x';

    /*Printing char after modification*/
    for(i=0; i<size; i++)
            fputc(*(ch+i),stdout);
    printf("\n");
    /* Finally unmap the file. This will flush out any changes. */
    munmap(map_base_addr, size);
    exit(0);
}

出力は次のようになります。

ABCDEFGHIJ
AbCDzFGxIJ
于 2016-12-14T12:13:12.967 に答える
3

わたしにはできる:

#include <stdio.h>

int main(int argc, char**argv) {
  int var = 7456;
  printf("Adress of var = %x, var=%d\n", &var, var);
  int *ptr = (int*)0x22cd28;
  printf(" ptr points to %x\n", ptr);
  *ptr = 123;
  printf("New value of var=%d\n", var);
  return 0;
}

プログラム出力:

Adress of var = 22cd28, var=7456
 ptr points to 22cd28
New value of var=123

ノート:

  1. アドレスは通常、すべての実行で同じではありません。例を試したとき、一致するアドレスを取得する前に3回実行する必要がありました。

  2. char*任意のアドレスを指すことができます(sizeof(char)= 1のため)。大きなオブジェクトへのポインタは、多くの場合、アドレス(通常は4で割り切れる1つ)に揃える必要があります。

于 2013-03-26T13:36:20.240 に答える
2

linux / windows / mac / whateverで実行している場合、あなたの質問はあまり意味がありません

http://en.wikipedia.org/wiki/Virtual_memory

これは、仮想メモリを使用せずにデバイスをプログラミングしている場合、またはオペレーティングシステム自体をプログラミングしている場合にのみ実行できます。

そうしないと、表示されるアドレスがRAM上の「実際の」アドレスではなく、オペレーティングシステムがそれらを実際のアドレスに変換します。仮想アドレスを実際のアドレスに変換するマップがない場合は、セグメンテーション違反が発生する可能性があります。セグメンテーション違反を引き起こす可能性のある他の理由があることに注意してください。

于 2013-03-26T13:40:49.367 に答える