演示应用工程通过 set_config("xt_sdk_platform_build_profile_path", ...) 完全覆盖平台默认的 app.ld,向链接器注入自定义段,并通过代码读取该段的符号。
背景机制
平台 platforms/windows/xmake.lua 通过 xt_sdk_build_profile_dir() 取 app.ld 并拼到 -T 参数:
local src_ld = path.join(xt_sdk_build_profile_dir(), "app.ld")
add_ldflags("-T " .. src_ld, {force = true})
xt_sdk_build_profile_dir() 解析顺序见 scripts/env.lua:
- xt_sdk_platform_build_profile_path(set_config,工程完全自定义)
- {target_path}/build_profile/(平台默认)
因此工程只需 set_config 指向自己的目录即可覆盖平台默认脚本。**当前 SDK 没有 ld 脚本 merge/include 机制,set_config 是全量替换。**
预期行为
graph LR
override["工程 build_profile_override/app.ld<br/>(覆盖)"]
default["平台 platforms/windows/simulator/build_profile/app.ld<br/>(默认, 不参与本次链接)"]
linker["ld (gcc -T app.ld)"]
exe["app.exe<br/>.build_profile_demo_section"]
override --> linker
default -. 被覆盖 .-> linker
linker --> exe
工程 xt_main.c 中:
- s_demo_marker 通过 __attribute__((section(".build_profile_demo_data"))) 放入自定义输入段。
- 工程的 app.ld 用 KEEP(*(.build_profile_demo_data)) 把它收集到输出段 .build_profile_demo_section,并导出首尾标号 __build_profile_demo_section_start/end。
- 运行时打印这组符号的地址和段大小,用于佐证该 ld 脚本被链接器实际采纳。
编译和运行
cd examples/build_system/build_profile_demo
xt --target windows/simulator fullclean build
.build/windows_simulator/app.exe
预期输出(地址每次启动会变):
[...][I] demo: marker addr=00007FF7... str="build_profile_demo_marker_in_custom_section"
[...][I] demo: section range=[00007FF7..., 00007FF7...) size=48
[...][I] build_profile_demo example
如何确认 ld 脚本真的被用了
# 1. 链接日志中 before_link 钩子打印的 src_ld 应指向工程 build_profile_override/app.ld
# [XT-SDK] before_link: linker script = ...\examples\build_system\build_profile_demo\build_profile_override\app.ld
# 2. PE 中能看到 .build_profile_demo_section 段
# objdump 取自 xt config 中配置的 windows toolchain (toolchain-path)
objdump -h .build/windows_simulator/app.exe | grep build_profile_demo
# 3. 导出符号存在
objdump -t .build/windows_simulator/app.exe | grep build_profile_demo_section
注意事项
- **Windows PE 加载器对齐约束**:新增段 VirtualAddress 必须按 SectionAlignment(MinGW 默认 0x1000)对齐,否则启动报 %1 不是有效的 Win32 应用程序(0xc1)。因此本示例写 ALIGN(0x1000),**不要照搬嵌入式/Linux 的 4 字节对齐**。
- **KEEP()**:防止 --gc-sections 清理掉未被代码引用的段。
- **INSERT AFTER**:必须放在 SECTIONS {} 块外部,且锚点段名必须存在于 MinGW 默认 ld 脚本中(<tt>.debug_gdb_scripts
是惯例锚点)。
- 覆盖目录名不强制叫 build_profile_override,只要 set_config 指向它即可;文件名**必须**是 app.ld。
- 如同时需要修改其它平台配置(分区表、NV 参数等),同一目录也可以放其它 build_profile 文件,平台侧按需读取。