当前位置: 首页 > wzjs >正文

嘉兴网站排名重庆制作手机网站

嘉兴网站排名,重庆制作手机网站,做网站找哪家公司,深圳商业营销厅设计公司对比两种不同的链接配置方式,主要体现在是否使用标准库、启动文件和系统调用支持方式的不同。下面详细逐项对比: 🧩 一、两个配置 配置 1:使用标准启动方式 nano libc LIBS -lc -lm -lnosys LDFLAGS $(MCU) -specsnano.specs…

对比两种不同的链接配置方式,主要体现在是否使用标准库、启动文件和系统调用支持方式的不同。下面详细逐项对比:


🧩 一、两个配置

配置 1:使用标准启动方式 + nano libc

LIBS = -lc -lm -lnosys
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=... -Wl,--gc-sections

这是比较 标准、温和的嵌入式设置,特点如下:

项目说明
-lc -lm链接标准 libc (newlib) 和 libm (math)
-lnosys提供空的系统调用桩(用于防止链接 _kill, _getpid 等失败)
-specs=nano.specs使用 newlib-nano,是更轻量的 libc 版本
没有 -nostdlib链接器仍然会使用 crt0.o 等默认启动代码
适合需要 printf, malloc 的工程,并希望较小代码体积

配置 2:完全裸机方式

LDFLAGS_GCC += \-nostdlib -nostartfiles \-specs=nosys.specs -specs=nano.specs

这是更为彻底控制的裸机配置

项目说明
-nostdlib不链接任何标准运行时(包括 libc, libgcc, crt0)
-nostartfiles不链接 crt0.o, crti.o, crtn.o 等启动代码
-specs=nosys.specs不启用系统调用(不自动拉入 _kill, _getpid
-specs=nano.specsnewlib-nano(但实际上 -nostdlib 会取消它除非手动链接)
❗ 必须自己提供:startup.s_start_exit_write 等运行时支持
适合极简/极控工程,如 bootloader、freestanding firmware

🆚 二、核心区别总结对比表:

特性配置 1:标准启动 + newlib-nano配置 2:裸机全控方式
启动文件(如 crt0.o✅ 自动链接❌ 不自动链接
标准 C 库 (newlib)✅ 默认链接 (-lc)❌ 不链接(你要手动提供函数或库)
printf, malloc✅ 可用❌ 除非你自己实现或手动链接
链接器脚本(-T linker.ld✅ 必须提供✅ 必须提供
系统调用符号(如 _sbrk✅ 自动拉入 nosys.specs 或你自定义❌ 你必须手动实现
控制程度⚪ 中等🔴 极高,完全裸机

🔧 三、用法建议:

使用标准库,但减小体积(推荐大多数项目)

LDFLAGS = -T linker.ld -specs=nano.specs -lc -lm -lnosys

适用于:USB、FreeRTOS、HAL、需要 printf、malloc 的项目。

你可以手动重定向 _write 来定制 printf 输出(如重定向到 UART、ITM)。


🔴 完全裸机 / 自己控制一切

LDFLAGS = -nostdlib -nostartfiles -T linker.ld -Wl,--gc-sections

适用于:bootloader、自定义运行时、不想用 libc 的极简项目。

你需要提供:

  • startup.s(或 _start
  • _sbrk, _write, _exit, _kill 这些裸函数
  • 不要使用 malloc、printf,或者自己实现

✅ 总结一句话:

  • 你希望轻量而不想完全脱离标准库时 👉 用配置 1(nano.specs, -lnosys, -lc -lm
  • 你希望完全掌控链接行为并自己写所有底层实现时 👉 用配置 2(-nostdlib -nostartfiles

当你自己写了 start.s(或 crt0.s)作为启动入口,并正确配置链接脚本使用你的 Reset_Handler_start就不会再链接系统自带的 crt0.o 或其他启动代码了


🔍 为什么不会链接系统的 crt0.o

默认情况下,GNU 工具链(如 arm-none-eabi-gcc)会自动链接标准 C 运行时启动代码 crt0.o(或 crtbegin.ocrtend.o):

  • 前提是你没有加 -nostartfiles-nostdlib
  • 或者你没有提供自定义的入口符号(比如 Reset_Handler

一旦你这样做了,就不会链接系统的启动文件:

  1. 自己写了 start.s/crt0.s,并提供了 _startReset_Handler
  2. 链接器参数中明确指定了 ENTRY(Reset_Handler) 或使用 -nostartfiles

这样,链接器认为你已经准备好了启动逻辑,不需要默认的启动文件,就不会链接它们了。


🚫 如果没注意,会隐式链接系统的 crt0

例如,如果你:

  • 没有 -nostartfiles
  • 没有自己的 start.s
  • 用的是 main(),但没指定入口函数

那编译器会自动加上类似 /lib/gcc/.../crt0.o 来完成初始化。

这就是为啥你有时看到“程序居然能跑 main 但你没写启动文件”——是因为系统偷偷帮你加了。


✅ 总结一句话

只要你提供了自己的 start.s 并控制链接过程(比如用 -nostartfiles 或指定入口),系统就不会再加 crt0.o,你就是自己控制运行时的“导演”。


完全正确 ✅!

链接器(ld)识别你是否需要默认的启动文件(如 crt0.o,关键就是:


🔍 识别入口的两个方式:

✅ 方式 1:在链接脚本中写 ENTRY(...)

ENTRY(Reset_Handler)
  • 明确告诉链接器程序从哪开始执行
  • 通常你写了自己的 start.s,就会加这个
  • 会跳过默认的 crt0.o

✅ 方式 2:链接器默认查找 _start

如果你没写 ENTRY(...),链接器默认使用 _start 作为入口:

.global _start
_start:...
  • 如果你提供了 _start,链接器会用它,不再链接系统的 _start(如 crt0.o)
  • 否则它会去找系统默认的启动文件来提供 _start

🔧 补充控制选项

GCC 选项意义
-nostartfiles不自动加 crt0.o 等启动文件(但还保留标准库)
-nostdlib更彻底,连 libc(如 newlib/libm) 都不加
-Wl,-e,XXX显式告诉链接器使用 XXX 作为程序入口,和 ENTRY() 是一样的意思
-T script.ld指定你自己的链接脚本,通常其中会有 ENTRY()

✅ 总结一句话:

链接器只要看到你指定了 ENTRY() 或你自己提供了 _start(或 Reset_Handler),它就不会再偷偷地加系统的 crt0.o


如果你想彻底掌控裸机程序启动过程,那就要做到:

  • ✅ 写你自己的 start.s
  • ✅ 提供 ENTRY(...)
  • ✅ 明确使用 -nostartfiles(可选)
  • ✅ 提供自己的链接脚本 .ld

说到 crt0(C runtime zero),它是程序启动时的“第一块敲门砖”,非常关键。


crt0 到底干了啥?

简单来说,crt0 是程序启动时执行的第一段代码,负责为你的程序搭建运行环境,让 main() 能正常运行。


crt0 的主要工作:

  1. 设置堆栈指针(Stack Pointer)
    在裸机环境下,程序一开始,堆栈指针(SP)没有被设置,crt0 会帮你把 SP 指向正确位置。

  2. 初始化数据段(.data)
    把存储在 Flash 中的初始化变量复制到 RAM。

  3. 清零 BSS 段(.bss)
    清理未初始化的全局变量区(把它们清成 0)。

  4. 调用全局构造函数
    对 C++ 来说,调用 __libc_init_array(),执行所有全局和静态对象的构造函数。

  5. 调用 main() 函数
    运行完初始化后,跳转到用户写的 main(),开始程序主体。

  6. 处理程序结束
    在裸机一般不会返回,但在某些环境,crt0 会处理 main 返回后的清理和退出。


形象比喻

  • crt0 就是舞台灯光和幕布的拉开动作,帮演员(main 函数)做好上场准备。

总结

crt0 负责
初始化硬件环境(堆栈指针)
复制初始化数据(.data)
清空未初始化数据区(.bss)
调用全局/静态构造函数(C++)
进入主函数 main()

当然可以!以下是一个适用于 ARM Cortex-M(如 STM32)最小 crt0.s 启动文件示例,内容包括堆栈初始化、.data/.bss 初始化和进入 main() 的全过程。


🔧 示例:最小裸机 crt0.s

    .syntax unified.cpu cortex-m3.thumb.global _start.global Reset_Handler.global main.extern __libc_init_array/* 堆栈顶地址,由链接脚本定义 */.section .isr_vector, "a", %progbits.word _estack          /* 初始堆栈指针 */.word Reset_Handler    /* 复位中断向量 */.text.thumb_func
Reset_Handler:
_start:/* 初始化 .data 段 */ldr r0, =_sidata       /* Flash 中 .data 的起始地址 */ldr r1, =_sdata        /* RAM 中 .data 的目标起始地址 */ldr r2, =_edata        /* RAM 中 .data 的结束地址 */
data_copy:cmp r1, r2ittt ltldrlt r3, [r0], #4strlt r3, [r1], #4blt data_copy/* 清零 .bss 段 */ldr r1, =_sbssldr r2, =_ebssmovs r3, #0
bss_zero:cmp r1, r2strlt r3, [r1], #4blt bss_zero/* 如果是 C++,调用构造函数数组 */bl __libc_init_array/* 跳转到 main */bl main/* 如果 main 返回,就停在这里 */
hang:b hang

🧩 链接脚本对应段(摘录)

你的链接脚本(.ld 文件)要定义这些符号:

_estack = ORIGIN(RAM) + LENGTH(RAM); /* 栈顶 */_sidata = LOADADDR(.data); /* .data 在 Flash 中的起始 */
_sdata = ADDR(.data);      /* .data 在 RAM 中的起始 */
_edata = .;                /* .data 在 RAM 中的结束 */_sbss = .;                 /* .bss 起始 */
_ebss = .;                 /* .bss 结束 */

✅ 支持 C/C++ 都可以

  • 如果你用 C++,__libc_init_array 会自动处理全局/静态对象构造。
  • 如果你只用 C,也可以不调用 __libc_init_array

适用范围

✅ 适用于:

  • STM32F1/F4/F7 等 Cortex-M 系列
  • 裸机工程(无 RTOS,无 HAL)

http://www.dtcms.com/wzjs/821580.html

相关文章:

  • 手机网站设计公司哪家专业整合营销传播成功案例
  • 个人网站设计结构图深圳自己的网站建设
  • 网站做简历模板运营商大数据精准营销
  • 上海网站关键词优化服务中国知名公司
  • 吉林珠海网站建设北京公司公示在哪个网站
  • 适合公司建设的网站优化网站方法
  • 中英文企业网站源码无锡做网站哪个公司好
  • 企业网站建设存在的不足小程序设计工具
  • 杭州市网站seo微信公众平台开发源代码
  • 五合一网站定制网站托管服务合同范本
  • 开发电子商务网站和开发新闻类网站什么异同企业手机网站建设信息
  • 亚马逊网站的建设和维护wordpress搜索结果带图代码
  • 网站建设的制度建设建设网站要不要钱百度贴吧
  • 自己做网站怎么租服务器wordpress 怎么用
  • 广州企业网站建设哪家服务好上海设计公司电话
  • 太阳能 技术支持 东莞网站建设免费注册163邮箱
  • 阿里云域名怎样做网站现在企业需要建设网站吗
  • 上海网站关键词西安网站制作工程师
  • 辽宁建设工程信息网执业人员海外网站推广优化专员
  • 合肥市住房和城乡建设厅网站手机网站怎么做沉浸式
  • 咨询学校网站开发费用手机vi设计公司
  • 惠州网站制作培训网站vps无法登陆
  • 做外围什么网站有客户花钱制作网站有什么好处
  • asp在网站制作中的作用泰安网站建设焦点网络
  • 如何网站增加域名客户推广渠道有哪些
  • 济南智能网站建设哪家好推广营销平台排名
  • 怎么做简单的微信浏览的网站rs232国产
  • 企业网站建设建议陕西企业营销型网站建设
  • 商城类网站能做响应式设计吗搜索网站仿站
  • 上海私人网站建设百度关键词屏蔽