自动分配到 GCC/C 中的特定 RAM 区域
Auto-Allocate to a specific RAM Area in GCC/C
抱歉我的英语不好,我有点难以解释我到底需要什么。
我正在使用 GCC 编译器将一些额外的代码添加到现有的二进制文件中。
在这种情况下,它是 PowerPC,但应该无关紧要。
我知道,在现有二进制文件的哪个位置我有可用的 RAM(我转储了完整的 RAM 以确保)但我需要手动定义每个 RAM 地址,目前我是这样做的:
// #ram.h
//8bit ram
uint8_t* xx1 = (uint8_t*) 0x807F00;
uint8_t* xx2 = (uint8_t*) 0x807F01;
//...and so on
// 16bit ram
uint16_t* xxx1 = (uint16_t*) 0x807F40;
uint16_t* xxx2 = (uint16_t*) 0x807F42;
//...and so on
// 32bit ram
uint32_t* xxxx1 = (uint32_t*) 0x807FA0;
uint32_t* xxxx2 = (uint32_t*) 0x807FA4;
//...and so on
我正在像这样访问我的变量:
void __attribute__ ((noinline)) silly_demo_function() {
#include "ram.h"
if (*xxx2>*xx1) {
*xxx3 = *xxx3 + *xx1;
}
return;
}
但这真的很无聊,如果我想将我的代码修补到另一个现有的二进制文件中,其中 available/free/unused ram 的位置可以完全不同,或者如果我 replacing/removing 中的某个值中间。我正在使用 8、16 和 32 位变量。
有没有办法,我可以定义一个区域,比如0x807F00到0x00808FFF,动态分配我的变量,编译器会在我的特定位置分配它?
我怀疑这里的大问题是那些地址是内存映射 IO(设备)而不是 RAM;不应被视为 RAM。
此外,我想说您可能应该将“不是 RAM 的设备”隐藏在抽象层后面,有点像设备驱动程序;部分是为了确保编译器符合由 IO 而不是 RAM 引起的任何约束(例如,被视为 volatile
,可能遵守任何访问大小限制,可能会处理任何缓存一致性管理);部分原因是 you/programmers 知道什么是 normal/fast/cached RAM,什么不是;部分原因是您可以用假代码替换“设备”以进行测试;部分是为了将其全部保存在一个明确定义的区域中。
例如;您可能有一个名为“src/devices.h”的头文件,其中包含:
#define xx1_address 0x807F00
.. 包装器代码可能是一个名为“src/devices/xx1.c”的文件,其中包含如下内容:
#include "src/devices.h"
static volatile uint8_t * xx1 = (uint8_t*) xx1_address;
uint8_t get_xx1(void) {
return *xx1;
}
void set_xx1(uint8_t x) {
*xx1 = x;
}
但是;根据这些设备的实际情况,您可能 need/want 一些更高级别的代码。例如,也许 xx1
是一个温度传感器,尝试设置它没有任何意义,并且您希望它缩放原始值,使其成为“摄氏度”,原始值的最高位value 用于指示错误情况(实际温度只有 7 位),因此包装器可能更像:
#include "src/devices.h"
#define xx1_offset -12.34
#define xx1_scale 1.234
static volatile uint8_t * xx1 = (uint8_t*) xx1_address;
float get_xx1_temperature(void) {
uint8_t raw_temp = *xx1;
if(raw_temp * 0x80 != 0) {
/* Error flag set */
return NAN;
}
/* No error */
return (raw_temp + xx1_offset) * xx1_scale;
}
同时,我想通了。
它就像在链接器指令中定义 .data、.bsss 和 .sbss 一样简单。
6 行代码和它的魅力。
抱歉我的英语不好,我有点难以解释我到底需要什么。 我正在使用 GCC 编译器将一些额外的代码添加到现有的二进制文件中。 在这种情况下,它是 PowerPC,但应该无关紧要。
我知道,在现有二进制文件的哪个位置我有可用的 RAM(我转储了完整的 RAM 以确保)但我需要手动定义每个 RAM 地址,目前我是这样做的:
// #ram.h
//8bit ram
uint8_t* xx1 = (uint8_t*) 0x807F00;
uint8_t* xx2 = (uint8_t*) 0x807F01;
//...and so on
// 16bit ram
uint16_t* xxx1 = (uint16_t*) 0x807F40;
uint16_t* xxx2 = (uint16_t*) 0x807F42;
//...and so on
// 32bit ram
uint32_t* xxxx1 = (uint32_t*) 0x807FA0;
uint32_t* xxxx2 = (uint32_t*) 0x807FA4;
//...and so on
我正在像这样访问我的变量:
void __attribute__ ((noinline)) silly_demo_function() {
#include "ram.h"
if (*xxx2>*xx1) {
*xxx3 = *xxx3 + *xx1;
}
return;
}
但这真的很无聊,如果我想将我的代码修补到另一个现有的二进制文件中,其中 available/free/unused ram 的位置可以完全不同,或者如果我 replacing/removing 中的某个值中间。我正在使用 8、16 和 32 位变量。
有没有办法,我可以定义一个区域,比如0x807F00到0x00808FFF,动态分配我的变量,编译器会在我的特定位置分配它?
我怀疑这里的大问题是那些地址是内存映射 IO(设备)而不是 RAM;不应被视为 RAM。
此外,我想说您可能应该将“不是 RAM 的设备”隐藏在抽象层后面,有点像设备驱动程序;部分是为了确保编译器符合由 IO 而不是 RAM 引起的任何约束(例如,被视为 volatile
,可能遵守任何访问大小限制,可能会处理任何缓存一致性管理);部分原因是 you/programmers 知道什么是 normal/fast/cached RAM,什么不是;部分原因是您可以用假代码替换“设备”以进行测试;部分是为了将其全部保存在一个明确定义的区域中。
例如;您可能有一个名为“src/devices.h”的头文件,其中包含:
#define xx1_address 0x807F00
.. 包装器代码可能是一个名为“src/devices/xx1.c”的文件,其中包含如下内容:
#include "src/devices.h"
static volatile uint8_t * xx1 = (uint8_t*) xx1_address;
uint8_t get_xx1(void) {
return *xx1;
}
void set_xx1(uint8_t x) {
*xx1 = x;
}
但是;根据这些设备的实际情况,您可能 need/want 一些更高级别的代码。例如,也许 xx1
是一个温度传感器,尝试设置它没有任何意义,并且您希望它缩放原始值,使其成为“摄氏度”,原始值的最高位value 用于指示错误情况(实际温度只有 7 位),因此包装器可能更像:
#include "src/devices.h"
#define xx1_offset -12.34
#define xx1_scale 1.234
static volatile uint8_t * xx1 = (uint8_t*) xx1_address;
float get_xx1_temperature(void) {
uint8_t raw_temp = *xx1;
if(raw_temp * 0x80 != 0) {
/* Error flag set */
return NAN;
}
/* No error */
return (raw_temp + xx1_offset) * xx1_scale;
}
同时,我想通了。
它就像在链接器指令中定义 .data、.bsss 和 .sbss 一样简单。 6 行代码和它的魅力。