对于嵌入式应用,通常需要访问外设寄存器的固定存储器位置.我发现这样做的标准方法如下:
// 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
Run Code Online (Sandbox Code Playgroud)
我理解它是如何工作的,但我不明白的是foo_reg的空间是如何分配的(即什么使链接器不能将另一个变量放在0x100?).可以在C级别保留空间,还是必须有一个链接器选项,指定不应将任何内容放在0x100.我正在使用GNU工具(gcc,ld等),所以我最感兴趣的是该工具集的具体细节.
有关我的架构的一些其他信息,以澄清问题:
我的处理器通过一组寄存器连接到FPGA,这些寄存器映射到处理器的常规数据空间(其中存在变量).所以我需要指向那些寄存器并阻止相关的地址空间.在过去,我使用了一个编译器,它有一个扩展用于从C代码中定位变量.我会将寄存器分组到一个结构中,然后将结构放在适当的位置:
typedef struct
{
BYTE reg1;
BYTE reg2;
...
} Registers;
Registers regs _at_ 0x100;
regs.reg1 = 0;
Run Code Online (Sandbox Code Playgroud)
实际上创建一个'Registers'结构保留了编译器/链接器眼中的空间.
现在,使用GNU工具,我显然没有在扩展.使用指针方法:
#define reg1 *(BYTE*)0x100;
#define reg2 *(BYTE*)0x101;
reg1 = 0
// or
#define regs *(Registers*)0x100
regs->reg1 = 0;
Run Code Online (Sandbox Code Playgroud)
这是一个没有操作系统且没有高级内存管理的简单应用程序.实质上:
void main()
{
while(1){
do_stuff();
}
}
Run Code Online (Sandbox Code Playgroud) 我有一个关于gcc链接器描述文件的非常具体的问题.我有一个嵌入式项目,必须确保主符号或主符号的地址出现在特定地址(Elf文件).
原因是,我有一个微控制器,上面有一个bootloader.此引导加载程序应在引导后调用主例程.出于这个原因,我必须在启动后提供跳转到的地址.
是否有一种方法可以使用链接描述文件强制符号始终位于表格顶部或输入地址,或者我甚至可以通过某种方式获取符号的地址以将其写回特定位置?
Thx提前.
我有一堆在没有该-fPIC选项的情况下编译的目标文件。因此对函数的调用不使用@PLT. (源代码是 C 语言并用 编译clang)。
我想将这些对象文件链接到一个共享库中,我可以使用dlopen. .so我需要这样做,因为在加载实际内容之前我必须进行大量设置。
但每次我尝试链接该-shared选项时,都会收到错误 -
创建共享库时不能使用
R_X86_64_PC32针对符号的重定位;splay_tree_lookup重新编译-fPIC
我从源代码重新编译没有任何问题。但我不想使用-fPIC. 这是我们正在开发自定义编译器的研究项目的一部分。PIC 不适用于我们试图在编译器中提供的保证类型。
是否有一些我可以使用的标志,ld以便它生成加载时重定位库。事实上,我没有搬家,也没什么问题。我可以为库提供基地址,dlopen如果虚拟地址不可用,则可能会失败。
我用来编译c文件的命令相当于 -
clang -m64 -c foo.c
Run Code Online (Sandbox Code Playgroud)
为了链接我正在使用
clang -m64 -shared *.o -o foo.so
Run Code Online (Sandbox Code Playgroud)
我说等效是因为它是一个自定义编译器(forked off clang)并且有一些额外的步骤。但它是等价的。
符号可以在一定的地址链接defsym如图所示这里。我的问题是,是否可以对部分进行相同的处理?也就是说,给定一些.o目标文件,是否可以指定节将被重定位到的基址?
或者,是否可以在最终链接之后重新设置部分的基础?也就是说,要更改二进制文件中某个节的地址,并使所有受重定位影响的信息(如该节中的相对分支等)都可以正确地重定位。
如果我的问题不清楚,我可以对其进行编辑并添加图像以更好地解释。