Phân tích file khởi động STM32 và script liên kết, cùng với việc thực hiện lại file khởi động STM32 bằng C

Trong phát triển STM32, file khởi động được cung cấp bởi ST offic chính cho toolchain GCC được viết bằng assembler ARM. Bài viết này sẽ phân tích cấu trúc của file đó và thực hiện lại nó bằng ngôn ngữ C.

Chúng ta sẽ lấy ví dụ từ dự án STM32F103C8T6 do ST cung cấp, bao gồm file khởi động startup_stm32f10x_md.s và script liên kết stm32_flash.ld. File khởi động này sử dụng assembler ARM để định nghĩa bảng vector ngoại lệ Cortex-M3, cũng như thực hiện hàm Reset_Handler bằng assembler. Script liên kết quy định cách liên kết chương trình và phân bổ vùng nhớ.

Phần mã nguồn C hoàn chỉnh cho file khởi động STM32F103 MD được tìm thấy ở phần phụ lục.

Phân tích script liên kết

Script liên kết nguyên bản được tìm thấy ở phần phụ lục STM32F103 MD.

Hàm khởi động

Script liên kết bắt đầu bằng việc khai báo hàm⼊⼝点, hay nói cách khác là hàm đầu tiên được gọi sau khi hệ thống khởi động: Reset_Handler.

/* Điểm⼊⼝ */
ENTRY(Reset_Handler)

Phân bổ vùng nhớ

Sau đó, script quy định vùng nhớ và cách sử dụng:

/* Khai báo vùng nhớ */
MEMORY
{
    RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 20K
    FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 64K
}

Thông tin về vùng nhớ như sau:

  • Vùng RAM, có thể đọc (r), viết (w) và chạy (x), kích thước 20K, bắt đầu từ địa chỉ 0x20000000.
  • Vùng FLASH, có thể đọc (r) và chạy (x), kích thước 64K, bắt đầu từ địa chỉ 0x8000000.

Đối với các model STM32F103 khác nhau, kích thước RAM và FLASH có thể thay đổi, do đó cần điều chỉnh các giá trị này để phù hợp với bộ vi xử lý đang sử dụng.

Cấu hình Heap và Stack

Phần tiếp theo là cấu hình stack:

/* Địa chỉ cao nhất của vùng nhớ stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);    /* end of RAM */

/* Tạo lỗi liên kết nếu heap và stack không đủ lớn trong RAM */
_Min_Heap_Size = 0x0;      /* Kích thước yêu cầu của heap */
_Min_Stack_Size = 0x400; /* Kích thước yêu cầu của stack */

Biến _estack xác định điểm bắt đầu của stack, do stack phát triển từ cao xuống thấp. Nếu không sử dụng malloc, có thể設置 _Min_Heap_Size thành 0.

Quy định các đoạn mã

SECTIONS
{
    /* ...... */
}

Cấu trúc SECTIONS trong script liên kết quy định cách phân bổ các đoạn mã. Mỗi đoạn mã (section) có một特성 riêng, như mã nguồn, dữ liệu đã khởi tạo, dữ liệu未 khởi tạo, vv.

Các đoạn mã thông dụng bao gồm .text .data .bss .rodata:

  • .text chứa mã nguồn nhị phân, các hàm đã biên dịch, có thể đọc và chạy nhưng không thể viết.
  • .data chứa các biến toàn cục đã khởi tạo có giá trị khác 0, có thể đọc và viết nhưng không chạy.
  • .bss chứa các biến toàn cục未 khởi tạo, sẽ được khởi tạo thành 0 khi chạy, có thể đọc và viết.
  • .rodata chứa các dữ liệu chỉ đọc như chuỗi, biến const, không thể chạy.

Trong GCC, chúng ta có thể chỉ định đoạn mã cho một biến hoặc hàm bằng cách sử dụng __attribute__((section("xxx"))):

__attribute__((section(".data"))) int a = 1;

Từ C23 trở lên, có thể sử dụng [[__attr]] để chỉ định đoạn mã:

[[gnu::section(".data")]] int a = 1;

Phân tích file khởi động STM32F103 MD

File khởi động STM32F103 MD thực hiện ba chức năng chính: định nghĩa bảng vector ngoại lệ, hiện thực hàm Reset_Handler, và cung cấp các hàm xử lý ngoại lệ mặc định cho các ngoại lệ chưa được xử lý.

Phân tích mã nguồn

Below là phân tích mã nguồn assembler và cách chuyển đổi sang C.

Khai báo biến toàn cục

.global g_pfnVectors
.global Default_Handler

Trong C, tương đương với việc khai báo các biến toàn cục:

extern uint32_t g_pfnVectors[];
extern void Default_Handler(void);

Định nghĩa các đoạn mã

/* Copy data segment initializers from flash to SRAM */
  movs	r1, #0
  b	LoopCopyDataInit

CopyDataInit:
	ldr	r3, =_sidata
	ldr	r3, [r3, r1]
	str	r3, [r0, r1]
	adds	r1, r1, #4

LoopCopyDataInit:
	ldr	r0, =_sdata
	ldr	r3, =_edata
	adds	r2, r0, r1
	cmp	r2, r3
	bcc	CopyDataInit
	ldr	r2, =_sbss
	b	LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
	movs	r3, #0
	str	r3, [r2], #4

LoopFillZerobss:
	ldr	r3, = _ebss
	cmp	r2, r3
	bcc	FillZerobss

Trong C, các đoạn mã này có thể được hiện thực như sau:

static void CopyDataInit(void)
{
    const uint32_t *src = (const uint32_t *)_sidata;
    const uint32_t *data_end = (const uint32_t *)_edata;
    uint32_t *data_begin = (uint32_t *)_sdata;

    while (data_begin < data_end)
    {
        *data_begin = *src;
        data_begin++;
        src++;
    }
}

static void FillZerobss(void)
{
    const uint32_t *bss_end = (const uint32_t *)_ebss;
    uint32_t *bss_begin = (uint32_t *)_sbss;

    while (bss_begin < bss_end)
    {
        *bss_begin = 0x00;
        bss_begin++;
    }
}

void Reset_Handler(void)
{
    CopyDataInit();
    FillZerobss();
    SystemInit();
    __libc_init_array();
    main();
    while(1){} // Vòng lặp vô hạn sau khi main() kết thúc
}

Bảng vector ngoại lệ

g_pfnVectors:
	.word	_estack
	.word	Reset_Handler
    // ...
    .word	BootRAM

Trong C, tương đương với một mảng các con trỏ hàm:

typedef void (*InterruptHandlerPtr_TypeDef)(void);
__attribute__((used, section(".isr_vector"))) const InterruptHandlerPtr_TypeDef g_pfnVectors[] = {
    /* Pointer to the top of the stack */
    (InterruptHandlerPtr_TypeDef)(uintptr_t)_estack,
    /* Các ngoại lệ hệ thống */
    Reset_Handler,
    NMI_Handler,
    HardFault_Handler,
    MemManage_Handler,
    BusFault_Handler,
    UsageFault_Handler,
    NULL,
    NULL,
    NULL,
    NULL,
    SVC_Handler,
    DebugMon_Handler,
    NULL,
    PendSV_Handler,
    SysTick_Handler,
    /* Các ngoại lệ ngoại vi */
    WWDG_IRQHandler,
    PVD_IRQHandler,
    TAMPER_IRQHandler,
    RTC_IRQHandler,
    FLASH_IRQHandler,
    RCC_IRQHandler,
    EXTI0_IRQHandler,
    EXTI1_IRQHandler,
    EXTI2_IRQHandler,
    EXTI3_IRQHandler,
    EXTI4_IRQHandler,
    DMA1_Channel1_IRQHandler,
    DMA1_Channel2_IRQHandler,
    DMA1_Channel3_IRQHandler,
    DMA1_Channel4_IRQHandler,
    DMA1_Channel5_IRQHandler,
    DMA1_Channel6_IRQHandler,
    DMA1_Channel7_IRQHandler,
    ADC1_2_IRQHandler,
    USB_HP_CAN1_TX_IRQHandler,
    USB_LP_CAN1_RX0_IRQHandler,
    CAN1_RX1_IRQHandler,
    CAN1_SCE_IRQHandler,
    EXTI9_5_IRQHandler,
    TIM1_BRK_IRQHandler,
    TIM1_UP_IRQHandler,
    TIM1_TRG_COM_IRQHandler,
    TIM1_CC_IRQHandler,
    TIM2_IRQHandler,
    TIM3_IRQHandler,
    TIM4_IRQHandler,
    I2C1_EV_IRQHandler,
    I2C1_ER_IRQHandler,
    I2C2_EV_IRQHandler,
    I2C2_ER_IRQHandler,
    SPI1_IRQHandler,
    SPI2_IRQHandler,
    USART1_IRQHandler,
    USART2_IRQHandler,
    USART3_IRQHandler,
    EXTI15_10_IRQHandler,
    RTC_Alarm_IRQHandler,
    USBWakeUp_IRQHandler,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    (InterruptHandlerPtr_TypeDef)BootRAM,
};

Hàm xử lý ngoại lệ mặc định

Default_Handler:
Infinite_Loop:
	b	Infinite_Loop

Trong C, hàm này được hiện thực như một vòng lặp vô hạn:

void Default_Handler(void)
{
    while (1)
    {
        /* Vòng lặp vô hạn */
    }
}

Phụ lục

STM32F103 MD C startup file

#include <stddef.h>
#include <stdint.h>

/* Các biến toàn cục được khai báo trong script liên kết */
extern uint8_t _estack[]; /** Top of Stack Pointer */

extern uint8_t _sidata[]; /**< Địa chỉ bắt đầu của dữ liệu khởi tạo trong FLASH */
extern uint8_t _sdata[];  /**< Địa chỉ bắt đầu của dữ liệu đã khởi tạo trong RAM */
extern uint8_t _edata[];  /**< Địa chỉ kết thúc của dữ liệu đã khởi tạo trong RAM */
extern uint8_t _sbss[];   /**< Địa chỉ bắt đầu của dữ liệu未 khởi tạo trong RAM */
extern uint8_t _ebss[];   /**< Địa chỉ kết thúc của dữ liệu未 khởi tạo trong RAM */

/** Giá trị đặc biệt cho chế độ boot từ RAM */
#define BootRAM 0xF108F85F

/** Định nghĩa loại con trỏ hàm xử lý ngoại lệ */
typedef void (*InterruptHandlerPtr_TypeDef)(void);

/* Khai báo các hàm.extern */
extern void SystemInit(void);        /**< Định nghĩa trong system_stm32f1xx.c */
extern int main(void);               /**< Định nghĩa trong main.c */
extern void __libc_init_array(void); /**< Hàm khởi tạo thư viện Newlib */

/* Prototype các hàm */
void Default_Handler(void);
__attribute__((weak)) void Reset_Handler(void); /**< Hàm reset sẽ không trả về */

/* Cung cấp các hàm xử lý ngoại lệ mặc định */
__attribute__((weak, alias("Default_Handler"))) void NMI_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void HardFault_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void MemManage_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void BusFault_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void UsageFault_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void SVC_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void DebugMon_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void PendSV_Handler(void);
__attribute__((weak, alias("Default_Handler"))) void SysTick_Handler(void);
/* Các handler ngoại vi */
__attribute__((weak, alias("Default_Handler"))) void WWDG_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void PVD_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TAMPER_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void RTC_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void FLASH_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void RCC_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI0_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI4_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel4_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel5_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel6_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void DMA1_Channel7_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void ADC1_2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USB_HP_CAN1_TX_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USB_LP_CAN1_RX0_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void CAN1_RX1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void CAN1_SCE_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI9_5_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_BRK_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_UP_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_TRG_COM_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM1_CC_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void TIM4_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C1_EV_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C1_ER_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C2_EV_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void I2C2_ER_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void SPI1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void SPI2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USART1_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USART2_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USART3_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void EXTI15_10_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void RTC_Alarm_IRQHandler(void);
__attribute__((weak, alias("Default_Handler"))) void USBWakeUp_IRQHandler(void);

/* Vector Table */
__attribute__((used, section(".isr_vector"))) const InterruptHandlerPtr_TypeDef g_pfnVectors[] = {
    /* Pointer to the top of the stack */
    (InterruptHandlerPtr_TypeDef)(uintptr_t)_estack,
    /* Các ngoại lệ hệ thống */
    Reset_Handler,
    NMI_Handler,
    HardFault_Handler,
    MemManage_Handler,
    BusFault_Handler,
    UsageFault_Handler,
    NULL,
    NULL,
    NULL,
    NULL,
    SVC_Handler,
    DebugMon_Handler,
    NULL,
    PendSV_Handler,
    SysTick_Handler,
    /* Các ngoại lệ ngoại vi */
    WWDG_IRQHandler,
    PVD_IRQHandler,
    TAMPER_IRQHandler,
    RTC_IRQHandler,
    FLASH_IRQHandler,
    RCC_IRQHandler,
    EXTI0_IRQHandler,
    EXTI1_IRQHandler,
    EXTI2_IRQHandler,
    EXTI3_IRQHandler,
    EXTI4_IRQHandler,
    DMA1_Channel1_IRQHandler,
    DMA1_Channel2_IRQHandler,
    DMA1_Channel3_IRQHandler,
    DMA1_Channel4_IRQHandler,
    DMA1_Channel5_IRQHandler,
    DMA1_Channel6_IRQHandler,
    DMA1_Channel7_IRQHandler,
    ADC1_2_IRQHandler,
    USB_HP_CAN1_TX_IRQHandler,
    USB_LP_CAN1_RX0_IRQHandler,
    CAN1_RX1_IRQHandler,
    CAN1_SCE_IRQHandler,
    EXTI9_5_IRQHandler,
    TIM1_BRK_IRQHandler,
    TIM1_UP_IRQHandler,
    TIM1_TRG_COM_IRQHandler,
    TIM1_CC_IRQHandler,
    TIM2_IRQHandler,
    TIM3_IRQHandler,
    TIM4_IRQHandler,
    I2C1_EV_IRQHandler,
    I2C1_ER_IRQHandler,
    I2C2_EV_IRQHandler,
    I2C2_ER_IRQHandler,
    SPI1_IRQHandler,
    SPI2_IRQHandler,
    USART1_IRQHandler,
    USART2_IRQHandler,
    USART3_IRQHandler,
    EXTI15_10_IRQHandler,
    RTC_Alarm_IRQHandler,
    USBWakeUp_IRQHandler,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    (InterruptHandlerPtr_TypeDef)BootRAM,
};

STM32F103 MD script liên kết

/* Entry Point */
ENTRY(Reset_Handler)

/* Specify the memory areas */
MEMORY
{
    RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 20K
    FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 64K
}

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);    /* end of RAM */

/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x0;      /* required amount of heap  */
_Min_Stack_Size = 0x400; /* required amount of stack */

SECTIONS
{
    /* The startup code goes first into FLASH */
    .isr_vector :
    {
        . = ALIGN(4);
        KEEP(*(.isr_vector)) /* Startup code */
        . = ALIGN(4);
    } >FLASH

    /* The program code and other data goes into FLASH */
    .text :
    {
        . = ALIGN(4);
        *(.text)           /* .text sections (code) */
        *(.text*)          /* .text* sections (code) */
        *(.rodata)         /* .rodata sections (constants, strings, etc.) */
        *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
        *(.glue_7)         /* glue arm to thumb code */
        *(.glue_7t)        /* glue thumb to arm code */

        KEEP (*(.init))
        KEEP (*(.fini))

        . = ALIGN(4);
        _etext = .;        /* define a global symbols at end of code */
    } >FLASH

    .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
    .ARM : {
        __exidx_start = .;
        *(.ARM.exidx*)
        __exidx_end = .;
    } >FLASH

    .ARM.attributes : { *(.ARM.attributes) } > FLASH

    .preinit_array     :
    {
        PROVIDE_HIDDEN (__preinit_array_start = .);
        KEEP (*(.preinit_array*))
        PROVIDE_HIDDEN (__preinit_array_end = .);
    } >FLASH
    .init_array :
    {
        PROVIDE_HIDDEN (__init_array_start = .);
        KEEP (*(SORT(.init_array.*)))
        KEEP (*(.init_array*))
        PROVIDE_HIDDEN (__init_array_end = .);
    } >FLASH
    .fini_array :
    {
        PROVIDE_HIDDEN (__fini_array_start = .);
        KEEP (*(.fini_array*))
        KEEP (*(SORT(.fini_array.*)))
        PROVIDE_HIDDEN (__fini_array_end = .);
    } >FLASH

    /* used by the startup to initialize data */
    _sidata = .;

    /* Initialized data sections goes into RAM, load LMA copy after code */
    .data : AT ( _sidata )
    {
        . = ALIGN(4);
        _sdata = .;        /* create a global symbol at data start */
        *(.data)           /* .data sections */
        *(.data*)          /* .data* sections */

        . = ALIGN(4);
        _edata = .;        /* define a global symbol at data end */
    } >RAM

    /* Uninitialized data section */
    . = ALIGN(4);
    .bss :
    {
        /* This is used by the startup in order to initialize the .bss secion */
        _sbss = .;         /* define a global symbol at bss start */
        __bss_start__ = _sbss;
        *(.bss)
        *(.bss*)
        *(COMMON)

        . = ALIGN(4);
        _ebss = .;         /* define a global symbol at bss end */
        __bss_end__ = _ebss;
    } >RAM

    PROVIDE ( end = _ebss );
    PROVIDE ( _end = _ebss );

    /* User_heap_stack section, used to check that there is enough RAM left */
    ._user_heap_stack :
    {
        . = ALIGN(4);
        . = . + _Min_Heap_Size;
        . = . + _Min_Stack_Size;
        . = ALIGN(4);
    } >RAM

    /* Remove information from the standard libraries */
    /DISCARD/ :
    {
        libc.a ( * )
        libm.a ( * )
        libgcc.a ( * )
    }
}

STM32F103 MD startup file

/**
  ******************************************************************************
  * @file      startup_stm32f10x_md.s
  * @author    MCD Application Team
  * @version   V3.5.1
  * @date      08-September-2021
  * @brief     Vector table for STM32F10x Medium Density Devices using Atollic toolchain.
  *            This module performs:
  *                - Set the initial SP
  *                - Set the initial PC == Reset_Handler,
  *                - Set the vector table entries with the exceptions ISR address
  *                - Configure the clock system
  *                - Jumps to main in the C library (which eventually
  *                  calls main()).
  * @param  None
  * @retval : None
*/

.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb

.global	g_pfnVectors
.global	Default_Handler

/* Copy data segment initializers from flash to SRAM */
  movs	r1, #0
  b	LoopCopyDataInit

CopyDataInit:
	ldr	r3, =_sidata
	ldr	r3, [r3, r1]
	str	r3, [r0, r1]
	adds	r1, r1, #4

LoopCopyDataInit:
	ldr	r0, =_sdata
	ldr	r3, =_edata
	adds	r2, r0, r1
	cmp	r2, r3
	bcc	CopyDataInit
	ldr	r2, =_sbss
	b	LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
	movs	r3, #0
	str	r3, [r2], #4

LoopFillZerobss:
	ldr	r3, = _ebss
	cmp	r2, r3
	bcc	FillZerobss

/* Call the clock system intitialization function.*/
    bl  SystemInit
/* Call static constructors */
    bl __libc_init_array
/* Call the application's entry point.*/
	bl	main
	bx	lr
.size	Reset_Handler, .-Reset_Handler

/**
 * @brief  Hàm xử lý ngoại lệ mặc định.
 *
 * @param  None
 * @retval : None
*/
    .section	.text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
	b	Infinite_Loop
	.size	Default_Handler, .-Default_Handler

/******************************************************************************
*
* Bảng vector ngoại lệ tối thiểu cho Cortex M3. Ghi chú rằng các cấu trúc phù hợp
* phải được đặt để đảm bảo rằng nó kết thúc ở địa chỉ vật lý 0x00000000.
*
******************************************************************************/
	.section	.isr_vector,"a",%progbits
	.type	g_pfnVectors, %object
	.size	g_pfnVectors, .-g_pfnVectors

g_pfnVectors:
	.word	_estack
	.word	Reset_Handler
	.word	NMI_Handler
	.word	HardFault_Handler
	.word	MemManage_Handler
	.word	BusFault_Handler
	.word	UsageFault_Handler
	.word	0
	.word	0
	.word	0
	.word	0
	.word	SVC_Handler
	.word	DebugMon_Handler
	.word	0
	.word	PendSV_Handler
	.word	SysTick_Handler
	.word	WWDG_IRQHandler
	.word	PVD_IRQHandler
	.word	TAMPER_IRQHandler
	.word	RTC_IRQHandler
	.word	FLASH_IRQHandler
	.word	RCC_IRQHandler
	.word	EXTI0_IRQHandler
	.word	EXTI1_IRQHandler
	.word	EXTI2_IRQHandler
	.word	EXTI3_IRQHandler
	.word	EXTI4_IRQHandler
	.word	DMA1_Channel1_IRQHandler
	.word	DMA1_Channel2_IRQHandler
	.word	DMA1_Channel3_IRQHandler
	.word	DMA1_Channel4_IRQHandler
	.word	DMA1_Channel5_IRQHandler
	.word	DMA1_Channel6_IRQHandler
	.word	DMA1_Channel7_IRQHandler
	.word	ADC1_2_IRQHandler
	.word	USB_HP_CAN1_TX_IRQHandler
	.word	USB_LP_CAN1_RX0_IRQHandler
	.word	CAN1_RX1_IRQHandler
	.word	CAN1_SCE_IRQHandler
	.word	EXTI9_5_IRQHandler
	.word	TIM1_BRK_IRQHandler
	.word	TIM1_UP_IRQHandler
	.word	TIM1_TRG_COM_IRQHandler
	.word	TIM1_CC_IRQHandler
	.word	TIM2_IRQHandler
	.word	TIM3_IRQHandler
	.word	TIM4_IRQHandler
	.word	I2C1_EV_IRQHandler
	.word	I2C1_ER_IRQHandler
	.word	I2C2_EV_IRQHandler
	.word	I2C2_ER_IRQHandler
	.word	SPI1_IRQHandler
	.word	SPI2_IRQHandler
	.word	USART1_IRQHandler
	.word	USART2_IRQHandler
	.word	USART3_IRQHandler
	.word	EXTI15_10_IRQHandler
	.word	RTC_Alarm_IRQHandler
	.word	USBWakeUp_IRQHandler
  .word	0
	.word	0
	.word	0
	.word	0
	.word	0
	.word	0
	.word	0
	.word	BootRAM          /* @0x108. Cho các thiết bị STM32F10x Medium Density boot từ RAM */

/*******************************************************************************
*
* Cung cấp các hàm xử lý ngoại lệ mặc định cho các ngoại lệ chưa được xử lý.
* Do chúng được khai báo là weak, bất kỳ hàm nào có cùng tên sẽ override các định nghĩa này.
*
*******************************************************************************/

  .weak	NMI_Handler
	.thumb_set NMI_Handler,Default_Handler

  .weak	HardFault_Handler
	.thumb_set HardFault_Handler,Default_Handler

  .weak	MemManage_Handler
	.thumb_set MemManage_Handler,Default_Handler

  .weak	BusFault_Handler
	.thumb_set BusFault_Handler,Default_Handler

	.weak	UsageFault_Handler
	.thumb_set UsageFault_Handler,Default_Handler

	.weak	SVC_Handler
	.thumb_set SVC_Handler,Default_Handler

	.weak	DebugMon_Handler
	.thumb_set DebugMon_Handler,Default_Handler

	.weak	PendSV_Handler
	.thumb_set PendSV_Handler,Default_Handler

	.weak	SysTick_Handler
	.thumb_set SysTick_Handler,Default_Handler

	.weak	WWDG_IRQHandler
	.thumb_set WWDG_IRQHandler,Default_Handler

	.weak	PVD_IRQHandler
	.thumb_set PVD_IRQHandler,Default_Handler

	.weak	TAMPER_IRQHandler
	.thumb_set TAMPER_IRQHandler,Default_Handler

	.weak	RTC_IRQHandler
	.thumb_set RTC_IRQHandler,Default_Handler

	.weak	FLASH_IRQHandler
	.thumb_set FLASH_IRQHandler,Default_Handler

	.weak	RCC_IRQHandler
	.thumb_set RCC_IRQHandler,Default_Handler

	.weak	EXTI0_IRQHandler
	.thumb_set EXTI0_IRQHandler,Default_Handler

	.weak	EXTI1_IRQHandler
	.thumb_set EXTI1_IRQHandler,Default_Handler

	.weak	EXTI2_IRQHandler
	.thumb_set EXTI2_IRQHandler,Default_Handler

	.weak	EXTI3_IRQHandler
	.thumb_set EXTI3_IRQHandler,Default_Handler

	.weak	EXTI4_IRQHandler
	.thumb_set EXTI4_IRQHandler,Default_Handler

	.weak	DMA1_Channel1_IRQHandler
	.thumb_set DMA1_Channel1_IRQHandler,Default_Handler

	.weak	DMA1_Channel2_IRQHandler
	.thumb_set DMA1_Channel2_IRQHandler,Default_Handler

	.weak	DMA1_Channel3_IRQHandler
	.thumb_set DMA1_Channel3_IRQHandler,Default_Handler

	.weak	DMA1_Channel4_IRQHandler
	.thumb_set DMA1_Channel4_IRQHandler,Default_Handler

	.weak	DMA1_Channel5_IRQHandler
	.thumb_set DMA1_Channel5_IRQHandler,Default_Handler

	.weak	DMA1_Channel6_IRQHandler
	.thumb_set DMA1_Channel6_IRQHandler,Default_Handler

	.weak	DMA1_Channel7_IRQHandler
	.thumb_set DMA1_Channel7_IRQHandler,Default_Handler

	.weak	ADC1_2_IRQHandler
	.thumb_set ADC1_2_IRQHandler,Default_Handler

	.weak	USB_HP_CAN1_TX_IRQHandler
	.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler

	.weak	USB_LP_CAN1_RX0_IRQHandler
	.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler

	.weak	CAN1_RX1_IRQHandler
	.thumb_set CAN1_RX1_IRQHandler,Default_Handler

	.weak	CAN1_SCE_IRQHandler
	.thumb_set CAN1_SCE_IRQHandler,Default_Handler

	.weak	EXTI9_5_IRQHandler
	.thumb_set EXTI9_5_IRQHandler,Default_Handler

	.weak	TIM1_BRK_IRQHandler
	.thumb_set TIM1_BRK_IRQHandler,Default_Handler

	.weak	TIM1_UP_IRQHandler
	.thumb_set TIM1_UP_IRQHandler,Default_Handler

	.weak	TIM1_TRG_COM_IRQHandler
	.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler

	.weak	TIM1_CC_IRQHandler
	.thumb_set TIM1_CC_IRQHandler,Default_Handler

	.weak	TIM2_IRQHandler
	.thumb_set TIM2_IRQHandler,Default_Handler

	.weak	TIM3_IRQHandler
	.thumb_set TIM3_IRQHandler,Default_Handler

	.weak	TIM4_IRQHandler
	.thumb_set TIM4_IRQHandler,Default_Handler

	.weak	I2C1_EV_IRQHandler
	.thumb_set I2C1_EV_IRQHandler,Default_Handler

	.weak	I2C1_ER_IRQHandler
	.thumb_set I2C1_ER_IRQHandler,Default_Handler

	.weak	I2C2_EV_IRQHandler
	.thumb_set I2C2_EV_IRQHandler,Default_Handler

	.weak	I2C2_ER_IRQHandler
	.thumb_set I2C2_ER_IRQHandler,Default_Handler

	.weak	SPI1_IRQHandler
	.thumb_set SPI1_IRQHandler,Default_Handler

	.weak	SPI2_IRQHandler
	.thumb_set SPI2_IRQHandler,Default_Handler

	.weak	USART1_IRQHandler
	.thumb_set USART1_IRQHandler,Default_Handler

	.weak	USART2_IRQHandler
	.thumb_set USART2_IRQHandler,Default_Handler

	.weak	USART3_IRQHandler
	.thumb_set USART3_IRQHandler,Default_Handler

	.weak	EXTI15_10_IRQHandler
	.thumb_set EXTI15_10_IRQHandler,Default_Handler

	.weak	RTC_Alarm_IRQHandler
	.thumb_set RTC_Alarm_IRQHandler,Default_Handler

	.weak	USBWakeUp_IRQHandler
	.thumb_set USBWakeUp_IRQHandler,Default_Handler

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****/

Thẻ: STM32 gcc ARM assembler C language Linker script

Đăng vào ngày 26 tháng 6 lúc 16:48