LK call_constructors

本文详细解析了Arm64架构下启动加载的过程及链接脚本配置,介绍了构造函数和析构函数的调用机制,以及不同内存段的分配与初始化过程。
lk/top/main.c
call_constructors:

static void call_constructors(void) {     void **ctor;

    ctor = &__ctor_list;     while (ctor != &__ctor_end) {         void (*func)(void);

        func = (void ( *)(void))*ctor;

        func();         ctor++;     } }

 

lk/arch/arm64/system-onesegment.ld :

OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64") OUTPUT_ARCH(aarch64)

ENTRY(_start) SECTIONS {     . = %KERNEL_BASE% + %KERNEL_LOAD_OFFSET%;

    /* text/read-only data */     /* set the load address to physical MEMBASE */     .text : AT(%MEMBASE% + %KERNEL_LOAD_OFFSET%) {         __code_start = .;         KEEP(*(.text.boot))         KEEP(*(.text.boot.vectab))         *(.text* .sram.text.glue_7* .gnu.linkonce.t.*)     }

    .interp : { *(.interp) }     .hash : { *(.hash) }     .dynsym : { *(.dynsym) }     .dynstr : { *(.dynstr) }     .rel.text : { *(.rel.text) *(.rel.gnu.linkonce.t*) }     .rela.text : { *(.rela.text) *(.rela.gnu.linkonce.t*) }     .rel.data : { *(.rel.data) *(.rel.gnu.linkonce.d*) }     .rela.data : { *(.rela.data) *(.rela.gnu.linkonce.d*) }     .rel.rodata : { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }     .rela.rodata : { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }     .rel.got : { *(.rel.got) }     .rela.got : { *(.rela.got) }     .rel.ctors : { *(.rel.ctors) }     .rela.ctors : { *(.rela.ctors) }     .rel.dtors : { *(.rel.dtors) }     .rela.dtors : { *(.rela.dtors) }     .rel.init : { *(.rel.init) }     .rela.init : { *(.rela.init) }     .rel.fini : { *(.rel.fini) }     .rela.fini : { *(.rela.fini) }     .rel.bss : { *(.rel.bss) }     .rela.bss : { *(.rela.bss) }     .rel.plt : { *(.rel.plt) }     .rela.plt : { *(.rela.plt) }     .init : { *(.init) } =0x9090     .plt : { *(.plt) }

    /* .ARM.exidx is sorted, so has to go in its own output section.  */     __exidx_start = .;     .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }     __exidx_end = .;

    .dummy_post_text : {      __code_end = .;     }

    .rodata : ALIGN(4096) {         __rodata_start = .;         __fault_handler_table_start = .;         KEEP(*(.rodata.fault_handler_table))         __fault_handler_table_end = .;         *(.rodata .rodata.* .gnu.linkonce.r.*)     }

    /*      * extra linker scripts tend to insert sections just after .rodata,      * so we want to make sure this symbol comes after anything inserted above,      * but not aligned to the next section necessarily.      */     .dummy_post_rodata : {         __rodata_end = .;     }

    .data : ALIGN(4096) {         /* writable data  */         __data_start_rom = .;         /* in one segment binaries, the rom data address is on top of the ram data address */         __data_start = .;         *(.data .data.* .gnu.linkonce.d.*)     }

    .ctors : ALIGN(8) {         __ctor_list = .;         KEEP(*(.ctors .init_array))         __ctor_end = .;     }     .dtors : ALIGN(8) {         __dtor_list = .;         KEEP(*(.dtors .fini_array))         __dtor_end = .;     }     .got : { *(.got.plt) *(.got) }     .dynamic : { *(.dynamic) }

    /*      * extra linker scripts tend to insert sections just after .data,      * so we want to make sure this symbol comes after anything inserted above,      * but not aligned to the next section necessarily.      */     .dummy_post_data : {         __data_end = .;     }

    /* unintialized data (in same segment as writable data) */     .bss : ALIGN(4096) {         __bss_start = .;         KEEP(*(.bss.prebss.*))         . = ALIGN(8);         __post_prebss_bss_start = .;         *(.bss .bss.*)         *(.gnu.linkonce.b.*)         *(COMMON)         . = ALIGN(8);         __bss_end = .;     }

    /* Align the end to ensure anything after the kernel ends up on its own pages */     . = ALIGN(4096);     _end = .;

    . = %KERNEL_BASE% + %MEMSIZE%;     _end_of_ram = .;

    /* Strip unnecessary stuff */     /DISCARD/ : { *(.comment .note .eh_frame) } }

 

### 关于_ATL_CSTRING_EXPLICIT_CONSTRUCTORS宏的定义和使用方法 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS 是一个与 ATL(Active Template Library)相关的宏,主要用于控制 CString 类构造函数的行为。CString 是 MFC 和 ATL 中常用的字符串类,提供了丰富的操作接口来处理字符串数据。 #### 宏的定义 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS 宏通常在 atlbase.h 文件中定义。当定义了此宏时,CString 的某些构造函数会被标记为 `explicit`,从而防止隐式的类型转换。例如: ```cpp #ifdef _ATL_CSTRING_EXPLICIT_CONSTRUCTORS #define EXPLICIT_CONSTRUCTOR explicit #else #define EXPLICIT_CONSTRUCTOR #endif class CString { public: EXPLICIT_CONSTRUCTOR CString(const char* psz); EXPLICIT_CONSTRUCTOR CString(const wchar_t* pch); // 其他构造函数... }; ``` 如果定义了 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS,那么上述构造函数将被标记为 `explicit`,从而避免类似以下代码中的隐式转换问题[^1]: ```cpp void Func(CString str) { // 函数实现 } // 如果没有定义 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS,下面的代码可以编译通过 Func("Hello"); // 如果定义了 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS,则需要显式转换 Func(CString("Hello")); ``` #### 使用场景 1. **防止隐式转换**:通过定义 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS,可以减少因隐式类型转换导致的潜在错误。 2. **提高代码可读性**:显式构造函数要求开发者明确地进行类型转换,从而增强代码的可维护性和清晰度。 3. **兼容性考虑**:在某些项目中,可能需要禁用此宏以保持向后兼容性或与其他代码库集成。 #### 示例代码 以下是一个简单的示例,展示了如何根据是否定义 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS 来影响 CString 的行为: ```cpp #include <atlbase.h> #include <atlstr.h> #ifdef _ATL_CSTRING_EXPLICIT_CONSTRUCTORS #define CONSTRUCTOR_TYPE "Explicit" #else #define CONSTRUCTOR_TYPE "Implicit" #endif int main() { // 显示当前的构造函数类型 printf("CString constructor is %s\n", CONSTRUCTOR_TYPE); // 测试 CString 构造 CString str1 = "Test"; // 隐式构造可能失败 CString str2(L"Test"); // 显式构造始终有效 return 0; } ``` 如果定义了 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS,上述代码中的 `CString str1 = "Test";` 可能会导致编译错误,除非显式地进行类型转换。 #### 注意事项 - 在使用 CString 时,建议检查项目的预定义宏设置,以确保了解当前的构造函数行为。 - 如果需要更改默认行为,可以通过在项目设置中定义或取消定义 _ATL_CSTRING_EXPLICIT_CONSTRUCTORS 来实现[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值