sizeof()的实现.

今天群里讨论了sizeof()函数的实现.下面用了两个宏实现了这功能.
  1. #define w_sizeof_a(T) ( ( long )( ( T* )0 + 1 ) ) 
  2. #define w_sizeof_b(T) ( ( long )( &T + 1 ) - ( long )&T )  
  3. #include <iostream>
  4. using namespace std;
  5. int main()
  6. {
  7.     int a[100][100][10];
  8.     cout<<w_sizeof_a(int)<<endl;
  9.     cout<<w_sizeof_a(int*)<<endl;
  10.     cout<<w_sizeof_a(char)<<endl;
  11.     cout<<w_sizeof_a(float)<<endl;
  12.     cout<<w_sizeof_a(double)<<endl;
  13.     cout<<w_sizeof_b(a)<<endl;
  14.     return 0;
  15. }

实现是利用了指针加一,跳过的字节数来实现.

SECTIONS { CORE_SEC(.rodata) : FLAGS(arl) { *(.rodata.farConst.cpu0.32bit) *(.rodata.farConst.cpu0.16bit) *(.rodata.farConst.cpu0.8bit) *(.rodata) *(.rodata.*) *(.gnu.linkonce.r.*) /* * Create the clear and copy tables that tell the startup code * which memory areas to clear and to copy, respectively. */ . = ALIGN(4); PROVIDE(__clear_table = .); LONG(0 + ADDR(.CPU2.zbss)); LONG(SIZEOF(.CPU2.zbss)); LONG(0 + ADDR(.CPU2.bss)); LONG(SIZEOF(.CPU2.bss)); LONG(0 + ADDR(.CPU2.lmubss)); LONG(SIZEOF(.CPU2.lmubss)); LONG(0 + ADDR(.CPU1.zbss)); LONG(SIZEOF(.CPU1.zbss)); LONG(0 + ADDR(.CPU1.bss)); LONG(SIZEOF(.CPU1.bss)); LONG(0 + ADDR(.CPU1.lmubss)); LONG(SIZEOF(.CPU1.lmubss)); LONG(0 + ADDR(.CPU0.zbss)); LONG(SIZEOF(.CPU0.zbss)); LONG(0 + ADDR(.CPU0.bss)); LONG(SIZEOF(.CPU0.bss)); LONG(0 + ADDR(.CPU0.lmubss)); LONG(SIZEOF(.CPU0.lmubss)); LONG(0 + ADDR(.zbss)); LONG(SIZEOF(.zbss)); LONG(0 + ADDR(.sbss)); LONG(SIZEOF(.sbss)); LONG(0 + ADDR(.bss)); LONG(SIZEOF(.bss)); LONG(0 + ADDR(.lmubss)); LONG(SIZEOF(.lmubss)); LONG(0 + ADDR(.OS_STACK_OSCORE_CORE0)); LONG(SIZEOF(.OS_STACK_OSCORE_CORE0)); LONG(0 + ADDR(.OS_STACK_OSCORE_CORE1)); LONG(SIZEOF(.OS_STACK_OSCORE_CORE1)); LONG(0 + ADDR(.OS_GLOBAL_NOCACHE_VAR)); LONG(SIZEOF(.OS_GLOBAL_NOCACHE_VAR)); LONG(-1); LONG(-1); PROVIDE(__clear_table_dlmu = .); LONG(0 + ADDR(.sbss4)); LONG(SIZEOF(.sbss4)); LONG(-1); LONG(-1); PROVIDE(__clear_table_powerOn = .); LONG(0 + ADDR(.zbss_powerOn)); LONG(SIZEOF(.zbss_powerOn)); LONG(-1); LONG(-1); PROVIDE(__copy_table = .); LONG(LOADADDR(.CPU2.zdata)); LONG(0 + ADDR(.CPU2.zdata)); LONG(SIZEOF(.CPU2.zdata)); LONG(LOADADDR(.CPU2.data)); LONG(0 + ADDR(.CPU2.data)); LONG(SIZEOF(.CPU2.data)); LONG(LOADADDR(.CPU2.lmudata)); LONG(0 + ADDR(.CPU2.lmudata)); LONG(SIZEOF(.CPU2.lmudata)); LONG(LOADADDR(.CPU1.zdata)); LONG(0 + ADDR(.CPU1.zdata)); LONG(SIZEOF(.CPU1.zdata)); LONG(LOADADDR(.CPU1.data)); LONG(0 + ADDR(.CPU1.data)); LONG(SIZEOF(.CPU1.data)); LONG(LOADADDR(.CPU1.lmudata)); LONG(0 + ADDR(.CPU1.lmudata)); LONG(SIZEOF(.CPU1.lmudata)); LONG(LOADADDR(.CPU0.zdata)); LONG(0 + ADDR(.CPU0.zdata)); LONG(SIZEOF(.CPU0.zdata)); LONG(LOADADDR(.CPU0.data)); LONG(0 + ADDR(.CPU0.data)); LONG(SIZEOF(.CPU0.data)); LONG(LOADADDR(.CPU0.lmudata)); LONG(0 + ADDR(.CPU0.lmudata)); LONG(SIZEOF(.CPU0.lmudata)); LONG(LOADADDR(.zdata)); LONG(0 + ADDR(.zdata)); LONG(SIZEOF(.zdata)); LONG(LOADADDR(.sdata)); LONG(0 + ADDR(.sdata)); LONG(SIZEOF(.sdata)); LONG(LOADADDR(.data)); LONG(0 + ADDR(.data)); LONG(SIZEOF(.data)); LONG(LOADADDR(.lmudata)); LONG(0 + ADDR(.lmudata)); LONG(SIZEOF(.lmudata)); LONG(LOADADDR(.sdata4)); LONG(0 + ADDR(.sdata4)); LONG(SIZEOF(.sdata4)); LONG(LOADADDR(.CPU0.psram_text)); LONG(0 + ADDR(.CPU0.psram_text)); LONG(SIZEOF(.CPU0.psram_text)); LONG(LOADADDR(.CPU1.psram_text)); LONG(0 + ADDR(.CPU1.psram_text)); LONG(SIZEOF(.CPU1.psram_text)); LONG(LOADADDR(.CPU2.psram_text)); LONG(0 + ADDR(.CPU2.psram_text)); LONG(SIZEOF(.CPU2.psram_text)); LONG(LOADADDR(.FLSLOADERRAM2CODE)); LONG(0 + ADDR(.FLSLOADERRAM2CODE)); LONG(SIZEOF(.FLSLOADERRAM2CODE)); LONG(LOADADDR(.data_xcp)); LONG(0 + ADDR(.data_xcp)); LONG(SIZEOF(.data_xcp)); LONG(LOADADDR(.data_xcp_Fake)); LONG(0 + ADDR(.data_xcp_Fake)); LONG(SIZEOF(.data_xcp_Fake)); LONG(LOADADDR(.CPU0.slow_data)); LONG(0 + ADDR(.CPU0.slow_data)); LONG(SIZEOF(.CPU0.slow_data)); LONG(LOADADDR(.CPU1.slow_data)); LONG(0 + ADDR(.CPU1.slow_data)); LONG(SIZEOF(.CPU1.slow_data)); LONG(LOADADDR(.OS_GLOBAL_NOCACHE_INITVAR)); LONG(0 + ADDR(.OS_GLOBAL_NOCACHE_INITVAR)); LONG(SIZEOF(.OS_GLOBAL_NOCACHE_INITVAR)); LONG(-1); LONG(-1); LONG(-1); PROVIDE(__copy_table_dlmu = .); LONG(-1); LONG(-1); LONG(-1); PROVIDE(__copy_table_powerOn = .); LONG(LOADADDR(.zdata_powerOn)); LONG(0 + ADDR(.zdata_powerOn)); LONG(SIZEOF(.zdata_powerOn)); LONG(-1); LONG(-1); LONG(-1); . = ALIGN(8); }> default_rom }
最新发布
09-29
你提供的这段代码是 **嵌入式系统中典型的 GNU ld 链接器脚本(Linker Script)** 的 `SECTIONS` 部分,其核心功能是: > ✅ 定义只读数据段 `.rodata` 的布局,并生成用于启动时初始化的 **清零表(clear table)** 和 **复制表(copy table)**。 这类脚本广泛应用于多核 MCU(如 Infineon TriCore、ARM Cortex-R 等)的汽车电子控制单元(ECU)开发中。 --- ### 回答问题: #### 1. 整体结构解析 ```ld SECTIONS { CORE_SEC(.rodata) : FLAGS(arl) { /* 收集所有 .rodata 相关节 */ *(.rodata.farConst.cpu0.32bit) ... *(.rodata.*) /* 生成 __clear_table:告诉启动代码哪些 BSS 段需要清零 */ PROVIDE(__clear_table = .); LONG(地址); LONG(大小); // 成对出现:每两项表示一个段 ... LONG(-1); LONG(-1); // 结束标志 PROVIDE(__clear_table_dlmu = .); ... // DLMU 专用清零段 LONG(-1); LONG(-1); PROVIDE(__clear_table_powerOn = .); ... // 上电清零段 LONG(-1); LONG(-1); /* 生成 __copy_table:告诉启动代码哪些 DATA 段需从 Flash 复制到 RAM */ PROVIDE(__copy_table = .); LONG(加载地址); LONG(运行地址); LONG(大小); // 三项一组 ... LONG(-1); LONG(-1); LONG(-1); PROVIDE(__copy_table_dlmu = .); ... PROVIDE(__copy_table_powerOn = .); ... } > default_rom } ``` --- ### 2. 关键语法与机制详解 #### ✅ `CORE_SEC(.rodata)` 和 `FLAGS(arl)` - `CORE_SEC(...)`:可能是宏,展开为标准 section 名称(如 `.rodata`) - `FLAGS(arl)`: - `a`: allocatable(可分配内存) - `r`: readable(可读) - `l`: loadable(需要从存储设备加载) 👉 表示这是一个位于 ROM/Flash 中、可加载的只读数据段。 #### ✅ `*(.rodata*)` 收集所有输入目标文件中的以下节: - `.rodata`:常规只读数据(字符串、const 变量等) - `.rodata.farConst.*`:远地址常量,可能用于跨段访问优化 - `.gnu.linkonce.r.*`:链接期去重的只读数据(如 inline 函数中的字符串) 这些都会被合并到输出文件的 `.rodata` 段中。 #### ✅ `PROVIDE(__clear_table = .)` 定义一个符号 `__clear_table`,指向当前位置(即清零表起始地址)。 `PROVIDE` 确保即使外部已定义也不会报错。 ##### 清零表格式(Zero Initialization Table): 每两个 `LONG` 表示: ```c struct { uint32_t ram_start_address; uint32_t byte_count; } clear_entry; ``` 多个条目后以 `(-1, -1)` 结束。 用途:在 C 运行时启动阶段(`_start` 或 `__low_level_init`),遍历此表并把对应 RAM 区域清零(相当于初始化 `.bss` 段)。 示例条目: ```ld LONG(0 + ADDR(.CPU0.bss)); LONG(SIZEOF(.CPU0.bss)); ``` → 将 `.CPU0.bss` 段所在的 RAM 区域清零。 #### ✅ `PROVIDE(__copy_table = .)` 定义复制表起始位置。 ##### 复制表格式(Copy Initialization Table): 每三个 `LONG` 表示: ```c struct { uint32_t flash_load_addr; // 数据在 Flash 中的位置(LOADADDR) uint32_t ram_run_addr; // 数据应在 RAM 中运行的位置(VMA) uint32_t byte_count; } copy_entry; ``` 以 `(-1,-1,-1)` 结束。 用途:将初始化过的全局变量(`.data` 段)从 Flash 复制到 RAM。 例如: ```ld LONG(LOADADDR(.data)); LONG(0 + ADDR(.data)); LONG(SIZEOF(.data)); ``` → 把存放在 Flash 中的 `.data` 初始值复制到 RAM 中的实际 `.data` 段。 > ⚠️ 注意:`.data` 在链接时有两个地址: > - **LMA (Load Memory Address)**:在 Flash 中的地址(由 `LOADADDR()` 获取) > - **VMA (Virtual Memory Address)**:在 RAM 中的运行地址(由 `ADDR(.data)` 获取) --- ### 3. 特殊段说明 | 段名 | 含义 | |------|------| | `.zbss`, `.zdata` | “Zero” 类型变量,编译器优化用法(某些架构特有) | | `.sbss`, `.sdata` | Small BSS/DATA,用于小对象快速访问(常见于嵌入式 ABI) | | `.lmubss`, `.lmudata` | LMI/LMU 内存区域(Local Memory Unit),高速本地内存 | | `.OS_STACK_OSCORE_*` | 多核操作系统栈 | | `.OS_GLOBAL_NOCACHE_*` | 不进缓存的共享变量(用于多核一致性) | | `.psram_text` | PSRAM 中存放的代码(外扩 RAM 执行) | | `.slow_data` | 低速外设相关数据 | --- ### 4. 地址计算函数说明 | 函数 | 含义 | |------|------| | `ADDR(sec)` | 返回 section 的 VMA(运行地址) | | `SIZEOF(sec)` | 返回 section 的大小(字节数) | | `LOADADDR(sec)` 或 `ATADDR(sec)` | 返回 LMA(加载地址,在 Flash 中的位置) | --- ### 5. 实际 C 启动代码如何使用这些表? 下面是一个典型的 **C runtime 初始化函数片段(用 C 写,但通常用汇编实现)** ```c void __initialize_data_and_bss(void) { extern long __clear_table[]; extern long __copy_table[]; // 清零 BSS 段 for (long *p = __clear_table; ; p += 2) { long *addr = (long *)p[0]; long count = p[1]; if (count == -1 && addr == (long*)-1) break; memset(addr, 0, count); } // 复制 DATA 段 for (long *p = __copy_table; ; p += 3) { long *flash_addr = (long *)p[0]; long *ram_addr = (long *)p[1]; long count = p[2]; if (count == -1 && flash_addr == (long*)-1) break; memcpy(ram_addr, flash_addr, count); } } ``` 这个函数会在 `_start` 中被调用,在 `main()` 之前执行,确保所有全局变量正确初始化。 --- ### 6. 输出位置:`> default_rom` 表示整个 `.rodata` 段(包括清零表和复制表)都放在名为 `default_rom` 的内存区域中(通常是 Flash 或伪 Flash)。 必须在 `MEMORY` 块中提前定义: ```ld MEMORY { default_rom (rx) : org = 0x80000000, len = 0x100000 default_ram (rwx): org = 0x40000000, len = 0x20000 } ``` --- ### ✅ 总结 | 功能 | 实现方式 | |------|----------| | 收集只读数据 | `*(.rodata*)` | | 初始化 `.bss` | 生成 `__clear_table`,记录各 `.bss` 段地址和大小 | | 初始化 `.data` | 生成 `__copy_table`,记录 Flash → RAM 映射关系 | | 支持多核 | 分别处理 CPU0/CPU1/CPU2 的段 | | 支持特殊内存 | 如 LMU、PSRAM、NOCACHE 区域 | | 自动化初始化 | 启动代码通过查表自动完成清零和复制 | --- ### 💡 提供完整可工作的 C 示例代码(模拟初始化逻辑) ```c #include <stdint.h> #include <string.h> // 由链接器生成的符号(声明即可) extern long __clear_table[]; extern long __copy_table[]; // 清零所有 BSS 段 void __clear_bss(void) { for (long *table = __clear_table; ; table += 2) { void *start = (void *)table[0]; long size = table[1]; if (start == (void*)-1UL && size == -1) break; memset(start, 0, size); } } // 复制所有 DATA 段 void __copy_data(void) { for (long *table = __copy_table; ; table += 3) { const void *src = (const void *)table[0]; // Flash void *dest = (void *)table[1]; // RAM long size = table[2]; if (src == (const void*)-1UL && size == -1) break; memcpy(dest, src, size); } } // 入口函数前调用 void _start(void) { __clear_bss(); __copy_data(); main(); while(1); } ``` ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值