web-dev-qa-db-ja.com

メモリ内の特定の絶対アドレスに変数を配置する方法(GCCを使用)

RealView ARM C Compiler supports 変数属性at(address)を使用して、指定されたメモリアドレスに変数を配置します:

int var __attribute__((at(0x40001000)));
var = 4;   // changes the memory located at 0x40001000

GCCには同様の変数属性がありますか?

26
Bas van Dijk

わかりませんが、次のような回避策を簡単に作成できます。

int *var = (int*)0x40001000;
*var = 4;

それはまったく同じではありませんが、ほとんどの状況で完全な代替品です。 GCCだけでなく、どのコンパイラでも機能します。

GCCを使用している場合、 GNU ld も使用していることを前提としています(もちろん、確実ではありません)。ldは変数 必要な場所に を配置することをサポートしています。

リンカにその仕事をさせることはかなり一般的だと思います。

@ribの回答に触発されて、絶対アドレスが制御レジスタ用である場合は、ポインタ定義にvolatileを追加します。 RAMだけの場合は問題ではありません。

21
Prof. Falken

セクション属性 とld リンカースクリプト を使用して、そのセクションに必要なアドレスを定義できます。これはおそらく他の方法よりも厄介ですが、オプションです。

15

あなたはあなたの質問に答えました、上のリンクにそれは述べています:

GNU GCC Compilerを使用すると、絶対メモリ位置にアクセスするためにポインタ定義のみを使用できます。次に例を示します。

#define IOPIN0         (*((volatile unsigned long *) 0xE0028000))
IOPIN0 = 0x4;

Btw http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Variable-Attributes.html#Variable%20Attributes

7
rib
    extern const uint8_t dev_serial[12];
    asm(".equ dev_serial, 0x1FFFF7E8");
/* or    asm("dev_serial = 0x1FFFF7E8"); */
    ...

    for (i = 0 ; i < sizeof(dev_serial); i++)
        printf((char *)"%02x ", dev_serial[i]);
4
user6409471

最小限の実行可能なリンカースクリプトの例

このテクニックは https://stackoverflow.com/a/4081574/895245 で言及されていましたが、ここで具体的な例を示します。

main.c

#include <stdio.h>

int __attribute__((section(".mySection"))) myvar = 0x9ABCDEF0;

int main(void) {
    printf("adr %p\n", (void*)&myvar);
    printf("val 0x%x\n", myvar);
    myvar = 0;
    printf("val 0x%x\n", myvar);
    return 0;
}

link.ld

SECTIONS
{
  .mySegment 0x12345678 : {KEEP(*(.mySection))}
}

GitHubアップストリーム

コンパイルして実行:

gcc -fno-pie -no-pie -o main.out -std=c99 -Wall -Wextra -pedantic link.ld main.c
./main.out

出力:

adr 0x12345678
val 0x9abcdef0
val 0x0

したがって、目的のアドレスに配置されていることがわかります。

これがGCCマニュアルのどこに記載されているかはわかりませんが、次の構文を使用します。

gcc link.ld main.c

指定されたリンカースクリプトを、使用されるデフォルトのスクリプトに追加するようです。

-fno-pie -no-pieが必要なのは、UbuntuツールチェーンがデフォルトでPIE実行可能ファイルを生成するように構成されているためです。これにより、Linuxカーネルは毎回別のアドレスに実行可能ファイルを配置し、実験を混乱させます。参照: gccおよびldでの位置に依存しない実行可能ファイルの-fPIEオプションとは何ですか?

TODO:コンパイルは警告を生成します:

/usr/bin/x86_64-linux-gnu-ld: warning: link.ld contains output sections; did you forget -T?

私は何か間違ったことをしていますか?それを取り除く方法は?参照: 警告を削除する方法:link.resには出力セクションが含まれます。 -Tを忘れましたか?

Ubuntu 18.10、GCC 8.2.0でテスト済み。