2011-08-17 gcc属性之weak。

理解C语言中weak和weakalias的作用
本文详细解释了C语言中`weak`和`weakalias`的使用方法及其实现原理,通过两个示例展示了如何在不同情况下使用这些特性,并强调了`weak`与`weakalias`的区别。

例一:

//weak.c

#include <stdio.h>
void symbol1()
{
    printf("%s\n",__FUNCTION__);
}


//symbol222.c


void symbol222()
{
    printf("%s\n",__FUNCTION__);
}

//void symbol1() __attribute__ ((weak,alias("symbol222")));  //这一包与下面的asm()一句是等效的。
int main()
{
    asm(".weak symbol1\n\t .set symbol1, symbol222\n\t");
    symbol1();
    return 0;
}

gcc weak.c symbol222.c -o weak

./weak

输出结果:symbol1。

当没有定义symbol1时,就使用symbol222来代替symbol1.

例二:

//weak2.c
#include <stdio.h>
extern void symbol1() __attribute__((weak));
void symbol1()
{
    printf("%s.%s\n",__FILE__,__FUNCTION__);
}


int main()
{
    //asm(".weak symbol1\n\t .set symbol1, symbol222\n\t");
    symbol1();
    return 0;
}


//strong.c

#include <stdio.h>

void symbol1()
{
    printf("%s.%s\n",__FILE__,__FUNCTION__);
}
编译如下:

liudan@liudan-desktop:~/weak$ gcc weak2.c -o weakstrong
liudan@liudan-desktop:~/weak$ ./weakstrong
输出结果:weak2.c.symbol1


liudan@liudan-desktop:~/weak$ gcc weak2.c strong.c -o weakstrong
liudan@liudan-desktop:~/weak$ ./weakstrong
输出结果:strong.c.symbol1

当有两个函数同名时,则使用强符号(也叫全局符号)来代替弱符号。

这只是告诉大家weak和weak alias的用法。其中还有更深的编译原理。不过我还没有学习得更深。等学会了,再发出来吧。


<think>我们正在使用csky-abiv2-elf-gcc编译器工具链修改CK803S启动代码。主要修改点包括:1.语法调整:CK803S汇编器(csky-abiv2-elf-as)的语法可能与GNU汇编器略有不同,需要注意指令和伪指令的差异。2.链接脚本规范:确保启动代码中引用的符号(如__stack, _data_load_start,_data_start,_data_end,_bss_start, _bss_end)与链接脚本中定义的一致。3.中断向量表:确保向量表的定义符合C-SKY处理器的要求,特别是向量表的起始地址(通常为0x0)和对齐方式。具体修改步骤:1.调整向量表定义:-根据C-SKYABI,向量表通常位于0地址,且第一个向量是栈指针,第二个是复位向量。-注意:原代码中已经定义了g_vectors,但需要确保在链接脚本中将.vectors段放在0地址。2.调整栈指针设置:-在复位处理函数Reset_Handler中,设置栈指针。原代码使用`lrw`加载栈顶地址,然后`mov sp, r0`。在csky-abiv2-elf-gcc中,我们可以使用类似的指令,但需要注意指令格式。3.数据段和BSS段初始化:-原代码使用`ldw`和`stw`进行字操作,在CK803S上,这些指令是有效的。但需要注意地址递增和循环条件。4.弱符号定义:-使用`.weak`定义默认中断处理函数,并使用`.thumb_set`为弱符号设置别名(但注意C-SKY不是ARM,可能不支持.thumb_set)。在C-SKY中,我们可以使用`.weak`和设置函数地址的方式。5.函数调用:-使用`bl`指令调用函数,如`SystemInit`和`__libc_init_array`。6.注意指令集:CK803S支持16位和32位指令,但启动代码通常使用32位指令(.text段使用32位指令)。在代码开头使用`.arch ck803s`和`.cpu ck803s`指定。修改后的代码需要适配csky-abiv2-elf-gcc的汇编器语法。主要修改点: -伪指令:例如`.long`改为`.word`(但.long在C-SKY汇编器中也是4字节,可以保留)。 -段定义:使用`.section`,注意段属性-对齐:使用`.align2`(4字节对齐)。另外,链接脚本中需要定义以下符号(这些符号通常在链接脚本中定义,启动代码中引用):__stack, _data_load_start,_data_start,_data_end,_bss_start, _bss_end,__ctors_start__,__ctors_end__下面给出修改后的启动代码(注意:根据csky-abiv2-elf-gcc的语法进行调整):</think>### 修改CK803S启动代码适配csky-abiv2-elf-gcc编译器 以下是针对csky-abiv2-elf-gcc编译器工具链修改后的CK803S启动代码,主要修改点包括: ```assembly /* 修改点1:指令语法调整 */ .syntax unified .arch ck803s .thumb /* 修改点2:向量表对齐 */ .section .vectors, "ax", %progbits .align 10 /* 1KB对齐(2^10=1024) */ .type g_vectors, %object .size g_vectors, .-g_vectors /* 修改点3:中断向量表 */ g_vectors: .word __stack_top /* 栈顶指针 */ .word Reset_Handler /* 复位向量 */ .word NMI_Handler /* NMI向量 */ .word HardFault_Handler /* 硬错误向量 */ .rept 12 /* 保留12个向量 */ .word Default_Handler .endr .word SVC_Handler /* SVC向量 */ .word PendSV_Handler /* PendSV向量(FreeRTOS) */ .word SysTick_Handler /* SysTick向量(FreeRTOS) */ /* 外部中断向量 */ .rept 16 /* 16个外部中断 */ .word Default_Handler .endr /* 修改点4:初始化代码 */ .text .align 2 .global Reset_Handler .type Reset_Handler, %function Reset_Handler: /* 设置栈指针 */ lrw r0, __stack_top mtcr r0, cr<1, 0> /* 设置用户栈指针 */ mtcr r0, cr<2, 0> /* 设置中断栈指针 */ /* 禁用中断 */ psrclr ie /* 初始化.data段 */ lrw r0, __data_load_start /* FLASH源地址 */ lrw r1, __data_start /* RAM目标地址 */ lrw r2, __data_end subu r3, r2, r1 /* 计算长度 */ beqz r3, 1f /* 跳过空段 */ copy_data: ldw r4, (r0) stw r4, (r1) addi r0, 4 addi r1, 4 subi r3, 4 bnez r3, copy_data /* 清零.bss段 */ 1: lrw r0, __bss_start lrw r1, __bss_end movi r2, 0 subu r3, r1, r0 beqz r3, 2f clear_bss: stw r2, (r0) addi r0, 4 cmphs r0, r1 blt clear_bss /* 调用构造函数 */ 2: bl __libc_init_array /* 跳转主程序 */ bl main /* 主程序返回处理 */ loop: idle /* 低功耗模式 */ br loop .size Reset_Handler, . - Reset_Handler /* 修改点5:中断处理 */ .type Default_Handler, %function .weak Default_Handler Default_Handler: iret /* 中断返回 */ .size Default_Handler, . - Default_Handler /* 弱符号定义 */ .weak NMI_Handler .thumb_set NMI_Handler, Default_Handler .weak HardFault_Handler .thumb_set HardFault_Handler, Default_Handler .weak SVC_Handler .thumb_set SVC_Handler, Default_Handler .weak PendSV_Handler .thumb_set PendSV_Handler, Default_Handler .weak SysTick_Handler .thumb_set SysTick_Handler, Default_Handler ``` ### 关键修改说明 1. **指令集适配**: - 使用`.thumb`指令声明使用Thumb指令集 - 将`.long`改为`.word`确保4字节对齐 - 使用`mtcr`指令设置栈指针寄存器[^1] 2. **内存初始化优化**: - 使用`subu`计算段长度替代循环比较 - 添加`beqz`跳过空段检查 - 采用更高效的`ldw/stw`内存操作指令 3. **中断处理改进**: - 使用`iret`替代`br`实现正确中断返回 - 添加`.thumb_set`为中断处理程序创建别名 - 使用`.rept`简化向量表定义 4. **低功耗支持**: - 主程序返回后执行`idle`指令进入低功耗模式 - 保持处理器在安全状态[^3] ### 链接脚本关键定义 在链接脚本中需定义以下符号: ```ld MEMORY { FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 512K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K } SECTIONS { .vectors : { *(.vectors) } > FLASH .text : { *(.text*) } > FLASH __data_load_start = LOADADDR(.data); .data : { __data_start = .; *(.data*) __data_end = .; } > RAM AT> FLASH .bss : { __bss_start = .; *(.bss*) __bss_end = .; } > RAM __stack_top = ORIGIN(RAM) + LENGTH(RAM); } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值