gcc链接脚本和启动文件详解

C代码生成可执行程序分为:预编译、编译、汇编、链接四个阶段。

  1. 预处理器把源程序聚合在一起,并把宏定义转换为源语言;
  2. 编译器根据预处理的源程序生成汇编程序;
  3. 汇编器处理汇编程序,生成可重定位的机器代码;
  4. 连接器将可重定位的目标代码和库文件连接到一起,生成可执行程序。

gcc链接脚本和启动文件详解_第1张图片
介绍几个常用命令,具体解释出自《The GNU linker》:

  1. SECTIONS命令
    gcc链接脚本和启动文件详解_第2张图片
  2. MEMORY命令
    gcc链接脚本和启动文件详解_第3张图片
  3. ENTRY命令
    在这里插入图片描述
    output sections:
    gcc链接脚本和启动文件详解_第4张图片
    下面是rtthread bsp下的一个连接脚本,逐字分析:
/*
 * linker script for GD32F4xx with GNU ld
 * bernard.xiong 2009-10-14
 */

/* Program Entry, set to mark it as "used" and avoid gc */
/* MEMORY命令,定义flash、ram的起始地址和长度,name也可改写成ROM和RAM,rx和rw表示属性,可读可执行和可读可写,ORIGIN可以写成org或o,LENGTH可以写成len或l */
MEMORY
{
    CODE (rx) : ORIGIN = 0x08000000, LENGTH = 64k /* 64/512KB flash */
    DATA (rw) : ORIGIN = 0x20000000, LENGTH = 256k /* 256KB sram */
}
/* entry point,也有其他写法 */
ENTRY(Reset_Handler)
/* 定义栈大小 */
_system_stack_size = 0x1000;

/* SECTIONS命令,定义了具体的flash和ram分布 */
SECTIONS
{
	/* gcc在flash中主要包含text、data和bss三个section,text存放code,data存放initialized data,bss存放uninitialized data */
    .text :
    {
    	/* .表示the location counter,At the start of the ‘SECTIONS’ command, the location counter
has the value ‘0’,ALIGN(4)表示4字节对齐 */
        . = ALIGN(4);
        /* _stext表示text section的起始地址,在cmbacktrace中用到了_stext */
        _stext = .;
        /* 当垃圾回收开启时‘--gc-sections’,使用KEEP防止被清除,isr_vector在startup文件中被定义,从这里开始存放中断向量表 */
        KEEP(*(.isr_vector))            /* Startup code */
        . = ALIGN(4);
        /* The ‘*’ is a wildcard which matches any file name. The expression ‘*(.text)’ means all ‘.text’ input sections in all input files. */
        *(.text)                        /* remaining code */
        /* 这里应该是text的结尾,怎么理解会比较好一点? */
        *(.text.*)                      /* remaining code */
        *(.rodata)                      /* read-only data (constants) */
        *(.rodata*)
        /* 没找到glue_7的解释 */
        *(.glue_7)
        *(.glue_7t)
        *(.gnu.linkonce.t*)

        /* section information for finsh shell */
        . = ALIGN(4);
        __fsymtab_start = .;
        KEEP(*(FSymTab))
        __fsymtab_end = .;
        . = ALIGN(4);
        __vsymtab_start = .;
        KEEP(*(VSymTab))
        __vsymtab_end = .;
        . = ALIGN(4);

        /* section information for initial. */
        . = ALIGN(4);
        /*  */
        __rt_init_start = .;
        /* typedef int (*init_fn_t)(void)
        #define SECTION(x) __attribute__((section(x)))
        #define INIT_EXPORT(fn, level) RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn." level) = fn
        init_fn_t是函数指针;
        SECTION(".rti_fn." level)则表示把对象放在由括号中的名称所指代的section中;
        INIT_EXPORT(rti_start, "0") => init_fn_t __rt_init_rti_start = rti_start SECTION(.rti_fn.0)
        SORT is an alias for SORT_BY_NAME
        实质就是将函数rti_start的首地址放到这个section中,并排序(启动顺序很重要) */
        KEEP(*(SORT(.rti_fn*)))
        __rt_init_end = .;
        . = ALIGN(4);

        . = ALIGN(4);
        /* cmbacktrace中用到了这个地址 */
        _etext = .;
    } > CODE = 0/* CODE section中 */

    /* .ARM.exidx is sorted, so has to go in its own output section.  */
    __exidx_start = .;
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
        /* This is used by the startup in order to initialize the .data secion */
        _sidata = .;
    } > CODE
    __exidx_end = .;

    /* .data section which is used for initialized data */

    .data : AT (_sidata)
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data secion */
        _sdata = . ;
		/* 所有初始化的数据 */
        *(.data)
        *(.data.*)
        *(.gnu.linkonce.d*)

        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .data secion */
        _edata = . ;
    } >DATA

    .stack : 
    {
    	/* 栈,起始地址和大小 */
        . = . + _system_stack_size;
        /* 栈顶地址四字节对齐 */
        . = ALIGN(4);
        /* cmbacktrace中用到 */
        _estack = .;
    } >DATA

    __bss_start = .;
    .bss :
    {
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss secion */
        /* 实际上startup中使用了__bss_start和__bss_end地址 */
        _sbss = .;
		/* 所有未初始化的数据 */
        *(.bss)
        *(.bss.*)
        /* COMMON好像没怎么见过,gcc中的说明是这样的:
        	A special notation is needed for common symbols, because in many object file formats
		common symbols do not have a particular input section. The linker treats common symbols
		as though they are in an input section named ‘COMMON’.
			You may use file names with the ‘COMMON’ section just as with any other input sections.
		You can use this to place common symbols from a particular input file in one section while
		common symbols from other input files are placed in another section. */
        *(COMMON)
		/* 结尾地址四字节对齐 */
        . = ALIGN(4);
        /* This is used by the startup in order to initialize the .bss secion */
        _ebss = . ;
        /* 暂时没找到说明 */
        *(.bss.init)
    } > DATA
    __bss_end = .;

    _end = .;
	/* 下面这些不知道干嘛的 */
    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /* DWARF debug sections.
     * Symbols in the DWARF debugging sections are relative to the beginning
     * of the section so we begin them at 0.  */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }
}

下面是对应的启动文件:

;/*
; * Copyright (c) 2006-2021, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date           Author       Notes
; * 2018-05-22     tanek        first implementation
; */
/* 指令语法集 统一的:ARM and THUMB instructions */
.syntax unified
/* Select the target processor */
.cpu cortex-m4
/* Select the floating-point unit to assemble for */
.fpu softvfp
/* This performs the same action as .code 16
thumb指令集,16bit */
.thumb

.global  g_pfnVectors
.global  Default_Handler
	/* 意思是isr_vector的section,"a",%progbits啥意思不太明白 */
    .section  .isr_vector,"a",%progbits
    /* 暂时没找到 */
    .type  g_pfnVectors, %object

g_pfnVectors:
	/* On the OpenRISC, the .word directive produces a 32 bit value */
    .word     _estack                           // Top of Stack
    .word     Reset_Handler                     // Reset Handler
    .word     NMI_Handler                       // NMI Handler
    .word     HardFault_Handler                 // Hard Fault Handler
    .word     MemManage_Handler                 // MPU Fault Handler
    .word     BusFault_Handler                  // Bus Fault Handler
    .word     UsageFault_Handler                // Usage Fault Handler
    .word     0                                 // Reserved
    .word     0                                 // Reserved
    .word     0                                 // Reserved
    .word     0                                 // Reserved
    .word     SVC_Handler                       // SVCall Handler
    .word     DebugMon_Handler                  // Debug Monitor Handler
    .word     0                                 // Reserved
    .word     PendSV_Handler                    // PendSV Handler
    .word     SysTick_Handler                   // SysTick Handler

    // external interrupts handler
    .word     WWDGT_IRQHandler                  // 16:Window Watchdog Timer
    .word     LVD_IRQHandler                    // 17:LVD through EXTI Line detect
    .word     TAMPER_STAMP_IRQHandler           // 18:Tamper and TimeStamp through EXTI Line detect
    .word     RTC_WKUP_IRQHandler               // 19:RTC Wakeup through EXTI Line
    .word     FMC_IRQHandler                    // 20:FMC
    .word     RCU_CTC_IRQHandler                // 21:RCU and CTC
    .word     EXTI0_IRQHandler                  // 22:EXTI Line 0
    .word     EXTI1_IRQHandler                  // 23:EXTI Line 1
    .word     EXTI2_IRQHandler                  // 24:EXTI Line 2
    .word     EXTI3_IRQHandler                  // 25:EXTI Line 3
    .word     EXTI4_IRQHandler                  // 26:EXTI Line 4
    .word     DMA0_Channel0_IRQHandler          // 27:DMA0 Channel0
    .word     DMA0_Channel1_IRQHandler          // 28:DMA0 Channel1
    .word     DMA0_Channel2_IRQHandler          // 29:DMA0 Channel2
    .word     DMA0_Channel3_IRQHandler          // 30:DMA0 Channel3
    .word     DMA0_Channel4_IRQHandler          // 31:DMA0 Channel4
    .word     DMA0_Channel5_IRQHandler          // 32:DMA0 Channel5
    .word     DMA0_Channel6_IRQHandler          // 33:DMA0 Channel6
    .word     ADC_IRQHandler                    // 34:ADC
    .word     CAN0_TX_IRQHandler                // 35:CAN0 TX
    .word     CAN0_RX0_IRQHandler               // 36:CAN0 RX0
    .word     CAN0_RX1_IRQHandler               // 37:CAN0 RX1
    .word     CAN0_EWMC_IRQHandler              // 38:CAN0 EWMC
    .word     EXTI5_9_IRQHandler                // 39:EXTI5 to EXTI9
    .word     TIMER0_BRK_TIMER8_IRQHandler      // 40:TIMER0 Break and TIMER8
    .word     TIMER0_UP_TIMER9_IRQHandler       // 41:TIMER0 Update and TIMER9
    .word     TIMER0_TRG_CMT_TIMER10_IRQHandler // 42:TIMER0 Trigger and Commutation and TIMER10
    .word     TIMER0_CC_IRQHandler              // 43:TIMER0 Capture Compare
    .word     TIMER1_IRQHandler                 // 44:TIMER1
    .word     TIMER2_IRQHandler                 // 45:TIMER2
    .word     TIMER3_IRQHandler                 // 46:TIMER3
    .word     I2C0_EV_IRQHandler                // 47:I2C0 Event
    .word     I2C0_ER_IRQHandler                // 48:I2C0 Error
    .word     I2C1_EV_IRQHandler                // 49:I2C1 Event
    .word     I2C1_ER_IRQHandler                // 50:I2C1 Error
    .word     SPI0_IRQHandler                   // 51:SPI0
    .word     SPI1_IRQHandler                   // 52:SPI1
    .word     USART0_IRQHandler                 // 53:USART0
    .word     USART1_IRQHandler                 // 54:USART1
    .word     USART2_IRQHandler                 // 55:USART2
    .word     EXTI10_15_IRQHandler              // 56:EXTI10 to EXTI15
    .word     RTC_Alarm_IRQHandler              // 57:RTC Alarm
    .word     USBFS_WKUP_IRQHandler             // 58:USBFS Wakeup
    .word     TIMER7_BRK_TIMER11_IRQHandler     // 59:TIMER7 Break and TIMER11
    .word     TIMER7_UP_TIMER12_IRQHandler      // 60:TIMER7 Update and TIMER12
    .word     TIMER7_TRG_CMT_TIMER13_IRQHandler // 61:TIMER7 Trigger and Commutation and TIMER13
    .word     TIMER7_CC_IRQHandler              // 62:TIMER7 Capture Compare
    .word     DMA0_Channel7_IRQHandler          // 63:DMA0 Channel7
    .word     EXMC_IRQHandler                   // 64:EXMC
    .word     SDIO_IRQHandler                   // 65:SDIO
    .word     TIMER4_IRQHandler                 // 66:TIMER4
    .word     SPI2_IRQHandler                   // 67:SPI2
    .word     UART3_IRQHandler                  // 68:UART3
    .word     UART4_IRQHandler                  // 69:UART4
    .word     TIMER5_DAC_IRQHandler             // 70:TIMER5 and DAC0 DAC1 Underrun error
    .word     TIMER6_IRQHandler                 // 71:TIMER6
    .word     DMA1_Channel0_IRQHandler          // 72:DMA1 Channel0
    .word     DMA1_Channel1_IRQHandler          // 73:DMA1 Channel1
    .word     DMA1_Channel2_IRQHandler          // 74:DMA1 Channel2
    .word     DMA1_Channel3_IRQHandler          // 75:DMA1 Channel3
    .word     DMA1_Channel4_IRQHandler          // 76:DMA1 Channel4
    .word     ENET_IRQHandler                   // 77:Ethernet
    .word     ENET_WKUP_IRQHandler              // 78:Ethernet Wakeup through EXTI Line
    .word     CAN1_TX_IRQHandler                // 79:CAN1 TX
    .word     CAN1_RX0_IRQHandler               // 80:CAN1 RX0
    .word     CAN1_RX1_IRQHandler               // 81:CAN1 RX1
    .word     CAN1_EWMC_IRQHandler              // 82:CAN1 EWMC
    .word     USBFS_IRQHandler                  // 83:USBFS
    .word     DMA1_Channel5_IRQHandler          // 84:DMA1 Channel5
    .word     DMA1_Channel6_IRQHandler          // 85:DMA1 Channel6
    .word     DMA1_Channel7_IRQHandler          // 86:DMA1 Channel7
    .word     USART5_IRQHandler                 // 87:USART5
    .word     I2C2_EV_IRQHandler                // 88:I2C2 Event
    .word     I2C2_ER_IRQHandler                // 89:I2C2 Error
    .word     USBHS_EP1_Out_IRQHandler          // 90:USBHS Endpoint 1 Out
    .word     USBHS_EP1_In_IRQHandler           // 91:USBHS Endpoint 1 in
    .word     USBHS_WKUP_IRQHandler             // 92:USBHS Wakeup through EXTI Line
    .word     USBHS_IRQHandler                  // 93:USBHS
    .word     DCI_IRQHandler                    // 94:DCI
    .word     0                                 // 95:Reserved
    .word     TRNG_IRQHandler                   // 96:TRNG
    .word     FPU_IRQHandler                    // 97:FPU
    .word     UART6_IRQHandler                  // 98:UART6
    .word     UART7_IRQHandler                  // 99:UART7
    .word     SPI3_IRQHandler                   // 100:SPI3
    .word     SPI4_IRQHandler                   // 101:SPI4
    .word     SPI5_IRQHandler                   // 102:SPI5
    .word     0                                 // 103:Reserved
    .word     TLI_IRQHandler                    // 104:TLI
    .word     TLI_ER_IRQHandler                 // 105:TLI Error
    .word     IPA_IRQHandler                    // 106:IPA

    .size  g_pfnVectors, .-g_pfnVectors

    .section  .text.Reset_Handler
    .weak  Reset_Handler
    .type  Reset_Handler, %function
Reset_Handler:
    ldr r1, =_sidata
    ldr r2, =_sdata
    ldr r3, =_edata

    subs r3, r2
    ble fill_bss_start

loop_copy_data:
    subs r3, #4
    ldr r0, [r1,r3]
    str r0, [r2,r3]
    bgt loop_copy_data

fill_bss_start:
    ldr r1, =__bss_start
    ldr r2, =__bss_end
    movs r0, 0
    subs r2, r1
    ble startup_enter

loop_fill_bss:
    subs r2, #4
    str r0, [r1, r2]
    bgt loop_fill_bss

startup_enter:
    bl SystemInit
    bl main

    /* Exception Handlers */
    .weak   NMI_Handler
    .type   NMI_Handler, %function
NMI_Handler:
    b       .
    .size   NMI_Handler, . - NMI_Handler

    .weak   MemManage_Handler
    .type   MemManage_Handler, %function
MemManage_Handler:
    b       .
    .size   MemManage_Handler, . - MemManage_Handler

    .weak   BusFault_Handler
    .type   BusFault_Handler, %function
BusFault_Handler:
    b       .
    .size   BusFault_Handler, . - BusFault_Handler

    .weak   UsageFault_Handler
    .type   UsageFault_Handler, %function
UsageFault_Handler:
    b       .
    .size   UsageFault_Handler, . - UsageFault_Handler

    .weak   SVC_Handler
    .type   SVC_Handler, %function
SVC_Handler:
    b       .
    .size   SVC_Handler, . - SVC_Handler

    .weak   DebugMon_Handler
    .type   DebugMon_Handler, %function
DebugMon_Handler:
    b       .
    .size   DebugMon_Handler, . - DebugMon_Handler

    .weak   PendSV_Handler
    .type   PendSV_Handler, %function
PendSV_Handler:
    b       .
    .size   PendSV_Handler, . - PendSV_Handler

    .weak   SysTick_Handler
    .type   SysTick_Handler, %function
SysTick_Handler:
    b       .
    .size   SysTick_Handler, . - SysTick_Handler

    /* IQR Handler */
    .section  .text.Default_Handler,"ax",%progbits
    .type  Default_Handler, %function
Default_Handler:
    b  .
    .size  Default_Handler, . - Default_Handler

    .macro  IRQ handler
    .weak   \handler
    .set    \handler, Default_Handler
    .endm

    IRQ WWDGT_IRQHandler
    IRQ LVD_IRQHandler
    IRQ TAMPER_STAMP_IRQHandler
    IRQ RTC_WKUP_IRQHandler
    IRQ FMC_IRQHandler
    IRQ RCU_CTC_IRQHandler
    IRQ EXTI0_IRQHandler
    IRQ EXTI1_IRQHandler
    IRQ EXTI2_IRQHandler
    IRQ EXTI3_IRQHandler
    IRQ EXTI4_IRQHandler
    IRQ DMA0_Channel0_IRQHandler
    IRQ DMA0_Channel1_IRQHandler
    IRQ DMA0_Channel2_IRQHandler
    IRQ DMA0_Channel3_IRQHandler
    IRQ DMA0_Channel4_IRQHandler
    IRQ DMA0_Channel5_IRQHandler
    IRQ DMA0_Channel6_IRQHandler
    IRQ ADC_IRQHandler
    IRQ CAN0_TX_IRQHandler
    IRQ CAN0_RX0_IRQHandler
    IRQ CAN0_RX1_IRQHandler
    IRQ CAN0_EWMC_IRQHandler
    IRQ EXTI5_9_IRQHandler
    IRQ TIMER0_BRK_TIMER8_IRQHandler
    IRQ TIMER0_UP_TIMER9_IRQHandler
    IRQ TIMER0_TRG_CMT_TIMER10_IRQHandler
    IRQ TIMER0_CC_IRQHandler
    IRQ TIMER1_IRQHandler
    IRQ TIMER2_IRQHandler
    IRQ TIMER3_IRQHandler
    IRQ I2C0_EV_IRQHandler
    IRQ I2C0_ER_IRQHandler
    IRQ I2C1_EV_IRQHandler
    IRQ I2C1_ER_IRQHandler
    IRQ SPI0_IRQHandler
    IRQ SPI1_IRQHandler
    IRQ USART0_IRQHandler
    IRQ USART1_IRQHandler
    IRQ USART2_IRQHandler
    IRQ EXTI10_15_IRQHandler
    IRQ RTC_Alarm_IRQHandler
    IRQ USBFS_WKUP_IRQHandler
    IRQ TIMER7_BRK_TIMER11_IRQHandler
    IRQ TIMER7_UP_TIMER12_IRQHandler
    IRQ TIMER7_TRG_CMT_TIMER13_IRQHandler
    IRQ TIMER7_CC_IRQHandler
    IRQ DMA0_Channel7_IRQHandler
    IRQ EXMC_IRQHandler
    IRQ SDIO_IRQHandler
    IRQ TIMER4_IRQHandler
    IRQ SPI2_IRQHandler
    IRQ UART3_IRQHandler
    IRQ UART4_IRQHandler
    IRQ TIMER5_DAC_IRQHandler
    IRQ TIMER6_IRQHandler
    IRQ DMA1_Channel0_IRQHandler
    IRQ DMA1_Channel1_IRQHandler
    IRQ DMA1_Channel2_IRQHandler
    IRQ DMA1_Channel3_IRQHandler
    IRQ DMA1_Channel4_IRQHandler
    IRQ ENET_IRQHandler
    IRQ ENET_WKUP_IRQHandler
    IRQ CAN1_TX_IRQHandler
    IRQ CAN1_RX0_IRQHandler
    IRQ CAN1_RX1_IRQHandler
    IRQ CAN1_EWMC_IRQHandler
    IRQ USBFS_IRQHandler
    IRQ DMA1_Channel5_IRQHandler
    IRQ DMA1_Channel6_IRQHandler
    IRQ DMA1_Channel7_IRQHandler
    IRQ USART5_IRQHandler
    IRQ I2C2_EV_IRQHandler
    IRQ I2C2_ER_IRQHandler
    IRQ USBHS_EP1_Out_IRQHandler
    IRQ USBHS_EP1_In_IRQHandler
    IRQ USBHS_WKUP_IRQHandler
    IRQ USBHS_IRQHandler
    IRQ DCI_IRQHandler
    IRQ TRNG_IRQHandler
    IRQ FPU_IRQHandler
    IRQ UART6_IRQHandler
    IRQ UART7_IRQHandler
    IRQ SPI3_IRQHandler
    IRQ SPI4_IRQHandler
    IRQ SPI5_IRQHandler
    IRQ TLI_IRQHandler
    IRQ TLI_ER_IRQHandler
    IRQ IPA_IRQHandler

你可能感兴趣的:(gcc链接脚本和启动文件详解)