Linker là một chương trình (giống như compiler, assembler,…) có tác dụng liên kết các file object (file *.o) và static library (*.a) thành một file binary duy nhất và có thể thực thi được. Linker Script là một file chứa các mã giúp cho Linker biết được vùng nào của các file đầu vào (object file, library file) phải được liên kết như thế nào để tạo file binary thực thi. Ví dụ,khi khai báo một vùng nhớ trong linker Script đại diện cho một vùng nhớ trên bộ nhớ; Tại mã chương trình ứng dụng, nếu một biến được khai báo với thuộc tính vùng đó thì Linker sẽ biết được cần phải sắp xếp biến vào vùng nhớ nào trong file đầu ra (.bin/.elf).
Bài viết này sẽ giúp các bạn hiểu về các mã trong linker script và có thể khai báo một vùng nhớ trong linker script.
Nội dung nên tham khảo trước khi đọc bài viết này: IC nhớ FLASH,SDRAM và mô hình bộ nhớ của vi điều khiển khi sử dụng bộ nhớ ngoài
1. Phân tích đoạn mã của Linker Script:
Dưới đây là ví dụ về cấu trúc một đoạn linker script của STM32:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
ENTRY(Reset_Handler) _estack = ORIGIN(RAM) + LENGTH(RAM); _Min_Heap_Size = 0x800 ; _Min_Stack_Size = 0x800 ; MEMORY {} /* Sections */ SECTIONS { .isr_vector : {} >FLASH .text : {} >FLASH .rodata : {} >FLASH .ARM.extab : {} >FLASH .ARM : {} >FLASH .preinit_array : {} >FLASH .init_array : {} >FLASH .fini_array : {} >FLASH _sidata = LOADADDR(.data); .data : {} >RAM AT> FLASH . = ALIGN(4); .bss : {} >RAM /* User_heap_stack section, used to check that there is enough "RAM" Ram type memory left */ ._user_heap_stack : {} >RAM .ext1flash_section : {} > EXT1FLASH .sdram_section 0xC0000000: {} >SDRAM |
Mã linker | Giải thích |
ENTRY(Reset_Handler) | Khai báo địa chỉ bắt đầu chương trình |
_estack = ORIGIN(RAM) + LENGTH(RAM); | Tính toán địa chỉ của stack (=địa chỉ cao nhất trong RAM) |
_Min_Heap_Size = 0x800 ; _Min_Stack_Size = 0x800 ; |
Minimum stack/heap: Thường dùng để linker check lỗi, kiểm tra đảm bảo sau khi trừ hết các khoảng không gian cho .bss và .data thì vẫn còn chừng đó không gian cho stack và heap. – Có thể set về 0 và chương trình vẫn chạy bthg miễn RAM còn không gian trống. |
MEMORY {} |
Khai báo các vùng không gian nhớ: RAM, FLASH, SDRAM,… |
SECTIONS { |
Cấu hình các vùng dữ liệu vào các vùng nhớ tương ứng |
.isr_vector : {} >FLASH |
Bảng các vector ngắt => Flash |
.text : {} >FLASH |
Mã chương trình => Flash |
.rodata : {} >FLASH |
Chứa các hằng (constant) => Flash |
.ARM.extab : {} >FLASH .ARM : .preinit_array : .init_array : .fini_array : |
Chưa cần quan tâm |
_sidata = LOADADDR(.data); | symbol _sidata được kí hiệu cho địa chỉ bắt đầu của vùng data |
.data : {} >RAM AT> FLASH . = ALIGN(4); |
Vùng chứa các biến được khởi tạo trong FLASH sẽ được load vào RAM khi chạy |
.bss : {} >RAM |
Vùng chứa các biến khởi tạo bằng 0 => RAM |
._user_heap_stack : {} >RAM |
Kiểm tra không gian trống cho heap stack dựa vào các chỉ số _Min_Heap_Size/_Min_Stack_Size |
.ext1flash_section : {} > EXT1FLASH |
Vùng nhớ flash ngoài => EXTI1FLASH |
.sdram_section 0xC0000000: {} >SDRAM |
Vùng nhớ RAM ngoài => SDRAM |
2.Khai báo một vùng nhớ trong linker script
Để khai báo một vùng nhớ trong linker script, ta viết đoạn mã như sau:
1 2 3 4 5 6 7 8 9 10 |
MEMORY { SDRAM (rw) : ORIGIN = 0xC0000000, LENGTH = 8M } .sdram_section 0xC0000000: { . = ALIGN(4); *(.buffer) *(.buffer*) } >SDRAM |
- Trong vùng MEMORY
- SDRAM: tên đại diện cho bộ nhớ cần khai báo ví dụ như SDRAM đại diện cho bộ nhớ RAM ngoài trong trường hợp này.
- rw: Thể hiện các quyền hạn của vùng nhớ; r là đọc (read), w là ghi (write), x (execution) có nghĩa là có thể thực thi lệnh từ bộ nhớ. Ví dụ: xrw nghĩa là có thể đọc ghi và thực thi lệnh từ bộ nhớ đó ví dụ như SRAM nội.
- ORIGIN: địa chỉ base của bộ nhớ. Ví dụ như RAM nội là 0x20000000, bộ nhớ Flash nội là 0x08000000, bộ nhớ SDRAM là 0xC0000000
- LENGTH: không gian của bộ nhớ mà người dùng có thể sử dụng ví dụ 8M (bytes) như trường hợp trên.
- Trong vùng “.sdram_section 0xC0000000”:
- .sdram_section: Tên vùng nhớ khai báo. Người dùng có thể đặt bất kỳ tên nào họ muốn ví dụ như “.Daylavungnhomoi”.
- 0xC0000000: Khai báo địa chỉ bắt đầu của vùng nhớ. Con số này có thể được thay đổi thành bất kì địa chỉ nào miễn sao giới hạn trong khoảng thấp nhất là 0xC0000000 và cao nhất 0xC07fffff đối với vùng nhớ SDRAM 8MB trên board STM32F7 DISCO
- . = ALIGN(4): Khai báo về việc căn chỉnh sắp xếp bộ nhớ mà cụ thể ở đây là 4 byte; Việc hiệu chỉnh con số trong align sẽ ảnh hưởng đến tốc độ và dung lượng lưu trữ của vùng nhớ
- *(.buffer): Tên các vùng nhớ dùng trong khai báo biến.
- >SDRAM: Vùng nhớ này được đưa vào bộ nhớ SDRAM khai báo ở trên
Theo dõi phần tiếp theo: Cấu hình ngoại vi giao tiếp FMC để sử dụng SRAM ngoài với vi điều khiển STM32.
Nhóm tác giả
Ng.Q.Phương, Ng.H.N.Thương, Ng.H.Phúc