RealView ARM C Compiler supports 変数属性at(address)
を使用して、指定されたメモリアドレスに変数を配置します:
int var __attribute__((at(0x40001000)));
var = 4; // changes the memory located at 0x40001000
GCCには同様の変数属性がありますか?
わかりませんが、次のような回避策を簡単に作成できます。
int *var = (int*)0x40001000;
*var = 4;
それはまったく同じではありませんが、ほとんどの状況で完全な代替品です。 GCCだけでなく、どのコンパイラでも機能します。
GCCを使用している場合、 GNU ld も使用していることを前提としています(もちろん、確実ではありません)。ldは変数 必要な場所に を配置することをサポートしています。
リンカにその仕事をさせることはかなり一般的だと思います。
@ribの回答に触発されて、絶対アドレスが制御レジスタ用である場合は、ポインタ定義にvolatile
を追加します。 RAMだけの場合は問題ではありません。
あなたはあなたの質問に答えました、上のリンクにそれは述べています:
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
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]);
最小限の実行可能なリンカースクリプトの例
このテクニックは 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))}
}
コンパイルして実行:
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でテスト済み。