2012-02-15 29 views
7

Khi xây dựng một dự án MCU trần kim loại gcc, bạn cần phải quan tâm đến việc khởi tạo các phần .data và .bss trong khi khởi động.Làm cách nào để biết phần .data cần lấy dữ liệu init từ đâu? (gcc linker)

Phần .bss khá dễ dàng vì tôi chỉ cần điền toàn bộ phần vào 0. Nhưng các biến trong phần .data cần có dữ liệu khởi tạo trong rom/flash và được sao chép trong khi khởi động.

Làm cách nào để biết dữ liệu có giá trị khởi tạo có thể được tìm thấy ở đâu?

Hãy lấy một ví dụ.

Hãy nói rằng tôi tạo ra hai biến toàn cục trong main.c

unsigned int my_global_variable_one = 1; 
unsigned int my_global_variable_two = 2; 

Sau đó, tôi có thể sử dụng objdump trên đối tượng tập tin để xem những gì phần họ sẽ được ở, nhưng tôi không thể tìm thấy bất cứ điều gì trong objdump ra đặt nơi dữ liệu init nên được đặt.

$ arm-none-eabi-objdump --syms main.o | grep my_global_variable 
00000000 g  O .data 00000004 my_global_variable_one 
00000004 g  O .data 00000004 my_global_variable_two 

Sau đó, tôi có thể xem kết quả của toàn bộ hệ thống, trong trường hợp này là main.elf.

$ arm-none-eabi-nm -n main.elf | grep my_global_variable 
20000000 D my_global_variable_one 
20000004 D my_global_variable_two 

Tôi có thể tìm nơi ở để tôi có thể sao chép dữ liệu? Tôi cần phải đưa gì vào kịch bản trình liên kết của mình?

Nó phải ở dạng như .text hoặc .rodata, nhưng làm sao tôi biết?

Làm cách nào để kiểm tra nơi dữ liệu init cho my_global_variable_one là?

Tôi có thể tìm thấy dữ liệu này ở đâu với bất kỳ lệnh nào trong số các lệnh binutils như readelf hoặc objdump không?

/Cảm ơn


Đây là trên STM32 (Cortex M3) MCU, và phiên bản CodeBench của gcc được sử dụng.

Trả lời

9

Trình biên dịch sẽ đặt tất cả mã và một số dữ liệu chỉ đọc trong phần .text. Cũng có thể có phần .rodata. Bạn có thể có kịch bản mối liên kết của bạn đặt trong một cái gì đó địa chỉ ROM như thế này:

. = <rom-base-address>; 
.rodata : { *(.rodata) } 
<other read-only sections go here> 
.text : { *(.text) } 

Trình biên dịch đặt tất cả các giá trị ban đầu của dữ liệu ghi trong phần .data, và tất cả các biểu tượng mà không có một giá trị ban đầu trong .bss. Các .bss là dễ dàng, bạn chỉ cần đặt trong RAM. Các .data muốn trở thành trong RAM tại thời gian chạy, nhưng trong ROM tại tải thời gian thực, và kịch bản mối liên kết cho phép bạn làm điều đó với AT keyword:

. = <ram-base-address>; 
.bss : { *(.bss) } 
.data : AT (ADDR (.text) + SIZEOF (.text)) 
     { *(.data) } 

Điều này có nghĩa rằng phần dữ liệu bây giờ có một LMA khác nhau và VMA (Tải địa chỉ bộ nhớ/địa chỉ bộ nhớ ảo). Chương trình của bạn sẽ mong đợi tìm dữ liệu tại VMA (địa chỉ thời gian chạy) nhưng dữ liệu thực sự tồn tại ở LMA (bạn có thể phải dạy flasher của bạn để làm điều này), ngay sau phần .text.

Nếu bạn cần tìm ra nơi để sao chép đến và từ đó bạn có thể tạo con trỏ trong tập lệnh trình liên kết. Vì vậy, sửa đổi các ví dụ trên như thế này:

.data : AT (ADDR (.text) + SIZEOF (.text)) 
     { _data_lma = LOADADDR(.data); _data_vma = .; 
      *(.data); 
      _data_size = SIZEOF (.data);} 

Sau đó bạn có thể làm memcpy (_data_vma, _data_lma, _data_size) trong mã khởi động của bạn (mặc dù bạn có thể phải tay mã mà trong lắp ráp?) Những biểu tượng sẽ xuất hiện để chương trình của bạn như liên tục globals giải quyết tại thời gian liên kết. Vì vậy, trong mã lắp ráp của bạn, bạn có thể có một cái gì đó như:

_data_lma_k: 
    .long _data_lma 

Sau đó, số sẽ được mã hóa cứng vào phần .text. Tất nhiên, cú pháp của trình assembler có thể khác trên nền tảng của bạn.

Để biết thêm thông tin, xem mối liên kết của nhãn hiệu here

+0

Vâng, tôi nhận thấy rằng các dữ liệu được nối sau phần .text, nhưng bạn đã giúp tôi có được đủ gần :) – Johan

Các vấn đề liên quan