固定地址变量在C [英] Fixed address variable in C

查看:160
本文介绍了固定地址变量在C的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于嵌入式应用程序,通常需要访问外设寄存器的固定内存位置。我发现这样做的标准方式是这样的:

  //访问注册foo_reg,它位于地址0x100 
#define foo_reg *(int *)0x100

foo_reg = 1; //写入foo_reg
int x = foo_reg; //从foo_reg

我明白了如何工作,但我不明白是怎么foo_reg的空间被分配(即什么使链接器不能将另一个变量置于0x100?)。空间可以保留在C级别,还是必须有一个链接器选项,指定什么都不应该位于0x100。我正在使用GNU工具(gcc,ld等),所以目前我对这个工具集的具体细节感兴趣。



有关我的解决问题的架构:



我的处理器通过一组映射到处理器的常规数据空间(其中变量存在)的寄存器连接到FPGA。所以我需要指向这些寄存器并阻止关联的地址空间。在过去,我使用了一个编译器,它具有一个用于从C代码定位变量的扩展。我将这个寄存器组合成一个结构体,然后将结构放在适当的位置:

  typedef struct 
{
BYTE reg1;
BYTE reg2;
...
}注册;

注册寄存器_at_ 0x100;

regs.reg1 = 0;

实际创建一个Registers结构保留了编译器/链接器眼中的空间。

现在,使用GNU工具,我显然没有扩展名。使用指针方法:

  #define reg1 *(BYTE *)0x100; 
#define reg2 *(BYTE *)0x101;
reg1 = 0

//或
#define regs *(Registers *)0x100
regs-> reg1 = 0;

这是一个简单的应用程序,没有操作系统,没有高级内存管理。基本上:

  void main()
{
while(1){
do_stuff );
}
}


解决方案

链接器和编译器不知道(当然没有你告诉任何东西)。您的平台的ABI的设计人员必须指定他们不在这些地址上分配对象。



所以,有时(我曾经工作过的平台)在虚拟地址空间中的一个范围,它直接映射到物理地址和另一个可以使用的范围通过用户空间进程来增长堆栈或分配堆内存。



您可以使用GNU ld的defsym选项在固定地址分配一些符号:

   -  defsym symbol = expression 

或者如果表达式比简单的算术,使用自定义链接描述文件。那就是你可以定义内存区域的地方,并告诉链接器应该给哪些区域/对象提供哪些区域。有关说明,请参阅此处。虽然这通常完全是您使用的工具链的作者。它们遵循ABI的规范,然后编写满足您平台要求的链接器脚本和汇编器/编译器后端。



顺便说一下,GCC有一个属性部分 ,您可以将其结构放入特定部分。然后,您可以告诉链接器将该部分放置到寄存器所在的区域。

 注册regs __attribute __((section(REGS))); 


For embedded applications, it is often necessary to access fixed memory locations for peripheral registers. The standard way I have found to do this is something like the following:

// access register 'foo_reg', which is located at address 0x100
#define foo_reg *(int *)0x100

foo_reg = 1;      // write to foo_reg
int x = foo_reg;  // read from foo_reg

I understand how that works, but what I don't understand is how the space for foo_reg is allocated (i.e. what keeps the linker from putting another variable at 0x100?). Can the space be reserved at the C level, or does there have to be a linker option that specifies that nothing should be located at 0x100. I'm using the GNU tools (gcc, ld, etc.), so am mostly interested in the specifics of that toolset at the moment.

Some additional information about my architecture to clarify the question:

My processor interfaces to an FPGA via a set of registers mapped into the regular data space (where variables live) of the processor. So I need to point to those registers and block off the associated address space. In the past, I have used a compiler that had an extension for locating variables from C code. I would group the registers into a struct, then place the struct at the appropriate location:

typedef struct
{ 
   BYTE reg1;
   BYTE reg2;
   ...
} Registers;

Registers regs _at_ 0x100;

regs.reg1 = 0;

Actually creating a 'Registers' struct reserves the space in the compiler/linker's eyes.

Now, using the GNU tools, I obviously don't have the at extension. Using the pointer method:

#define reg1 *(BYTE*)0x100;
#define reg2 *(BYTE*)0x101;
reg1 = 0

// or
#define regs *(Registers*)0x100
regs->reg1 = 0;

This is a simple application with no OS and no advanced memory management. Essentially:

void main()
{
    while(1){
        do_stuff();
    }
}

解决方案

Your linker and compiler don't know about that (without you telling it anything, of course). It's up to the designer of the ABI of your platform to specify they don't allocate objects at those addresses.

So, there is sometimes (the platform i worked on had that) a range in the virtual address space that is mapped directly to physical addresses and another range that can be used by user space processes to grow the stack or to allocate heap memory.

You can use the defsym option with GNU ld to allocate some symbol at a fixed address:

--defsym symbol=expression

Or if the expression is more complicated than simple arithmetic, use a custom linker script. That is the place where you can define regions of memory and tell the linker what regions should be given to what sections/objects. See here for an explanation. Though that is usually exactly the job of the writer of the tool-chain you use. They take the spec of the ABI and then write linker scripts and assembler/compiler back-ends that fulfill the requirements of your platform.

Incidentally, GCC has an attribute section that you can use to place your struct into a specific section. You could then tell the linker to place that section into the region where your registers live.

Registers regs __attribute__((section("REGS")));

这篇关于固定地址变量在C的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆