Mã khởi động bằng kim loại trần để khởi tạo vùng Cortex M3 .bss


10

Tôi đã phát triển lấy cảm hứng từ đây một mã khởi động bằng kim loại trần cho vỏ não M3. Tuy nhiên, tôi gặp phải vấn đề sau: giả sử tôi khai báo một biến toàn cục chưa được khởi tạo, nói về kiểu char không dấu trong main.c

#include ...
unsigned char var; 
...
int main()
{
 ...
}

điều này làm cho vùng .bss trong STM32 f103 bắt đầu tại _BSS_START = 0x20000000 và kết thúc tại _BSS_END = 0x20000001. Bây giờ, mã khởi động

    unsigned int * bss_start_p = &_BSS_START; 
    unsigned int * bss_end_p = &_BSS_END;

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }

cố gắng khởi tạo để không toàn bộ khu vực .bss. Tuy nhiên, bên trong vòng lặp while đó, con trỏ tăng lên với 4 byte, do đó sau một bước bss_start_p = 0x20000004 do đó nó sẽ luôn khác với bss_end_p dẫn đến một vòng lặp vô hạn, v.v.

Có bất kỳ giải pháp tiêu chuẩn cho điều này? Tôi có thể giả sử "buộc" bằng cách nào đó kích thước của vùng .bss là bội số của 4 không? Hoặc tôi nên sử dụng một con trỏ để ký tự không dấu để đi qua vùng .bss? Có lẽ một cái gì đó như:

    unsigned char * bss_start_p = (unsigned char *)(&_BSS_START); 
    unsigned char * bss_end_p = (unsigned char *)(&_BSS_END);

    while(bss_start_p != bss_end_p)
    {
        *bss_start_p = 0;
        bss_start_p++;
    }
```

sử dụng ít hơn. bootstraps được viết trong hội đồng cho một lý do. trước hết bạn đã tạo ra một vấn đề .data. Nó là một thứ gà và trứng để sử dụng / giả sử rằng C hoạt động mà bạn dựa vào .text, .bss và .data ở mức tối thiểu, nhưng bạn đang viết mã C để đảm bảo mã C sẽ hoạt động, sử dụng những thứ trong mã C yêu cầu bootstrap có thể được viết bằng mã C dựa trên C làm việc.
old_timer

mã để sao chép .data qua rất giống với .bss, nhưng nếu bạn viết nó giống như mã ở trên thì bạn cần sao chép .data để sao chép .data.
old_timer

Câu trả lời:


15

Như bạn nghi ngờ, điều này xảy ra vì kiểu dữ liệu int không dấu có kích thước 4 byte. Mỗi *bss_start_p = 0;câu lệnh thực sự xóa bốn byte của khu vực bss.

Phạm vi bộ nhớ bss cần được căn chỉnh chính xác. Bạn có thể chỉ cần xác định _BSS_START và _BSS_END sao cho tổng kích thước là bội số của bốn, nhưng điều này thường được xử lý bằng cách cho phép tập lệnh liên kết xác định vị trí bắt đầu và dừng.

Ví dụ, đây là phần liên kết trong một trong các dự án của tôi:

.bss (NOLOAD) : ALIGN(4)
{
    __bss_start__ = .;
    *(.bss)
    . = ALIGN(4);
    __bss_end__ = .;
} >RAM

Các ALIGN(4)báo cáo chăm sóc mọi thứ.

Ngoài ra, bạn có thể muốn thay đổi

while(bss_start_p != bss_end_p)

đến

while(bss_start_p < bss_end_p).

Điều này sẽ không ngăn chặn sự cố (vì bạn có thể xóa 1-3 byte nhiều hơn bạn muốn), nhưng nó có thể giảm thiểu tác động :)


@CMarius Sau khi phản ánh, tôi nghĩ ý tưởng con trỏ char của bạn sẽ hoạt động tốt, mặc dù nó sẽ đòi hỏi nhiều chu kỳ hơn. Nhưng tôi không chắc liệu sẽ có vấn đề tiếp theo với vùng bộ nhớ tiếp theo không được sắp xếp hay không, vì vậy tôi sẽ không đề cập đến nó trong câu trả lời của mình ...
bitsmack

1
while(bss_start_p < bss_end_p - 1)theo sau là việc xóa byte theo phạm vi bộ nhớ còn lại sẽ loại bỏ mối quan tâm cuối cùng.
glglgl

4

Giải pháp chuẩn là memset():

#include <string.h>
memset(&_BSS_START, 0, &_BSS_END - &_BSS_START)

Nếu bạn không thể sử dụng thư viện chuẩn, thì bạn sẽ phải quyết định xem có ổn không trong trường hợp của bạn để làm tròn kích thước của vùng nhớ lên đến 4 byte và tiếp tục sử dụng unsigned int *; hoặc nếu bạn cần nghiêm ngặt về nó, trong trường hợp bạn cần sử dụng unsigned char *.

Nếu bạn làm tròn kích thước, như trong vòng lặp đầu tiên của bạn, thì bss_start_pthực sự có thể kết thúc lớn hơn bss_end_pnhưng điều đó dễ dàng đối phó với một so sánh ít hơn <thay vì kiểm tra bất bình đẳng.

Tất nhiên, bạn cũng có thể lấp đầy hầu hết vùng nhớ bằng các lần chuyển 32 bit và chỉ một vài byte cuối cùng với chuyển 8 bit, nhưng đó là công việc nhiều hơn để kiếm được ít tiền, đặc biệt ở đây khi đó chỉ là một đoạn mã khởi động.


1
Đồng ý rất nhiều với việc sử dụng memset(). Nhưng căn chỉnh đến 4 byte là nhiều hay ít phải. Vậy tại sao không làm điều đó?
Codo

3
không có cách nào hình dạng hoặc hình thức là giải pháp tiêu chuẩn cho bootstrap để sử dụng memset, điều đó thật điên rồ.
old_timer

bạn không sử dụng cùng một ngôn ngữ để khởi động ngôn ngữ đó
old_timer

2
mã bootstrap và tập lệnh liên kết đã kết hôn rất nhiều, bạn sẽ thấy phổ biến rằng tập lệnh liên kết căn chỉnh và kích thước .bss trên ít nhất một ranh giới 4 byte để cải thiện điền (trong bootstrap) theo 4 lần theo hướng dẫn thời gian (giả sử (tối thiểu) 32 bit bus là điển hình cho nhánh nhưng có ngoại lệ)
old_timer

3
@old_timer, hàm C tiêu chuẩn để đặt bộ nhớ thành một giá trị cụ thể memset()và C là thứ mà chúng dường như đang lập trình. Việc thực hiện đơn giản memset()cũng chỉ là vòng lặp đó, không giống như nó phụ thuộc vào nhiều thứ khác. Vì đó là một vi điều khiển, tôi cũng cho rằng không có liên kết động hay xảy ra (và nhìn vào liên kết, không có, đó chỉ là một cuộc gọi đến main()sau vòng lặp zeroing đó), vì vậy trình biên dịch sẽ có khả năng thả memset()vào đó cùng với các chức năng khác (hoặc để thực hiện nó nội tuyến).
ilkkachu

4

Chỉ cần thay đổi !=thành <. Dù sao đó thường là một cách tiếp cận tốt hơn, vì nó giải quyết các vấn đề như thế này.


3

Có vô số trang web và ví dụ khác. Nhiều ngàn nếu không phải hàng vạn. Có những thư viện c nổi tiếng với các tập lệnh liên kết và mã boostrap, đặc biệt là newlib, glibc nhưng có những thư viện khác bạn có thể tìm thấy. Bootstraping C với C không có ý nghĩa.

Câu hỏi của bạn đã được trả lời, bạn đang cố gắng thực hiện một so sánh chính xác về những điều có thể không chính xác, nó có thể không bắt đầu trên một ranh giới đã biết hoặc kết thúc trên một ranh giới đã biết. Vì vậy, bạn có thể làm ít hơn nhưng nếu mã không hoạt động với một so sánh chính xác thì điều đó có nghĩa là bạn đang bỏ qua .bss vào phần tiếp theo có thể hoặc không thể gây ra những điều xấu xảy ra, vì vậy chỉ cần thay thế bằng một ít hơn là không giải pháp.

Vì vậy, ở đây đi TL; DR là tốt. Bạn không khởi động một ngôn ngữ với ngôn ngữ đó, bạn có thể thoát khỏi nó với ngôn ngữ đó, nhưng bạn đang chơi với lửa khi bạn làm điều đó. Nếu bạn chỉ đang học cách làm điều này, bạn cần phải thận trọng, không phải là may mắn ngu ngốc hay sự thật mà bạn chưa khám phá ra.

Kịch bản liên kết và mã bootstrap có mối quan hệ rất mật thiết, họ đã kết hôn, tham gia cùng nhau, bạn không phát triển cái này mà không có cái kia dẫn đến thất bại lớn. Và thật không may, tập lệnh liên kết được xác định bởi trình liên kết và ngôn ngữ lắp ráp được xác định bởi trình biên dịch chương trình để khi bạn thay đổi các công cụ dự kiến ​​sẽ phải viết lại cả hai. Tại sao lắp ráp ngôn ngữ? Nó không cần bootstrap, ngôn ngữ biên dịch thường làm. C thực hiện nếu bạn không muốn giới hạn việc sử dụng ngôn ngữ của mình, Bắt đầu với một thứ rất đơn giản có yêu cầu cụ thể về công cụ tối thiểu, bạn không giả sử các biến .bss bằng 0 (làm cho mã ít đọc hơn nếu biến không bao giờ được khởi tạo trong ngôn ngữ đó , hãy cố gắng tránh điều này, điều này không đúng với các biến cục bộ vì vậy phải có mặt trên quả bóng khi bạn sử dụng nó. Mọi người hãy tránh xa toàn cầu, vậy tại sao chúng ta lại nói về .bss và .data ??? (toàn cầu là tốt cho công việc cấp độ này nhưng đó là một chủ đề khác)) quy tắc khác cho giải pháp đơn giản là không khởi tạo các biến trong khai báo, thực hiện trong mã. vâng, đốt cháy nhiều flash hơn, bạn thường có rất nhiều, không phải tất cả các biến đều được khởi tạo với các hằng số mà cuối cùng là hướng dẫn tiêu thụ.

Bạn có thể nói từ thiết kế cortex-m rằng họ có thể đã nghĩ rằng không có mã bootstrap nào cả nên không hỗ trợ .data và .bss. Hầu hết mọi người sử dụng toàn cầu không thể sống mà không có ở đây:

Tôi có thể làm cho điều này tối thiểu hơn nhưng là một ví dụ chức năng tối thiểu cho tất cả cortex-ms bằng cách sử dụng công cụ gnu, tôi không nhớ phiên bản nào bạn có thể bắt đầu với 5.xx hoặc hơn thông qua 9.xx hiện tại tôi đã chuyển các tập lệnh liên kết ở đâu đó khoảng 3. xx hoặc 4.xx khi tôi học được nhiều hơn và khi gnu thay đổi thứ gì đó đã phá vỡ cái đầu tiên của tôi.

bootstrap:

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

điểm vào mã C:

void bounce ( unsigned int );

unsigned int a;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

tập lệnh liên kết.

MEMORY
{
    rom : ORIGIN = 0x00000000, LENGTH = 0x1000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .rodata : { *(.rodata*) } > rom
    .bss : { *(.bss*) } > ram
}

Tất cả những thứ này có thể nhỏ hơn và vẫn hoạt động, thêm một số thứ bổ sung ở đây chỉ để xem nó tại nơi làm việc.

xây dựng và liên kết tối ưu.

00000000 <_start>:
   0:   20001000
   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

00000014 <reset>:
  14:   f000 f804   bl  20 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
    ...

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

đối với một số nhà cung cấp, bạn muốn sử dụng 0x08000000 hoặc 0x01000000 hoặc các địa chỉ tương tự khác khi đèn flash được ánh xạ ở đó và được nhân đôi thành 0x00000000 trong một số chế độ khởi động. một số chỉ có rất nhiều đèn flash được nhân đôi ở 0x00000000, vì vậy bạn muốn có điểm bảng vectơ tại không gian flash ứng dụng chứ không phải không. vì nó là bảng vector dựa trên tất cả các công trình.

đầu tiên lưu ý cortex-ms là máy chỉ ngón tay cái và vì bất kỳ lý do gì họ thực thi một địa chỉ chức năng ngón tay cái, có nghĩa là lsbit là số lẻ. Biết các công cụ của bạn, các lệnh .thumb_func cho trình biên dịch gnu biết rằng nhãn tiếp theo là địa chỉ hàm ngón tay cái. làm điều +1 trong bảng sẽ dẫn đến thất bại, đừng cố làm điều đó, hãy làm đúng. có nhiều cách khác để biên dịch hàm gnu để khai báo hàm, đây là cách tiếp cận tối thiểu.

   4:   00000015
   8:   0000001b
   c:   0000001b
  10:   0000001b

Nó sẽ không khởi động nếu bạn không nhận được bảng vector đúng.

có thể chỉ cần vectơ con trỏ ngăn xếp (có thể đặt bất cứ thứ gì vào đó nếu bạn muốn tự đặt con trỏ ngăn xếp trong mã) và vectơ thiết lập lại. Tôi đặt bốn ở đây không có lý do cụ thể. Thường đặt 16 nhưng muốn rút ngắn ví dụ này.

Vì vậy, tối thiểu một bootstrap C cần phải làm là gì? 1. đặt con trỏ ngăn xếp 2. zero .bss 3. sao chép .data 4. nhánh tới hoặc gọi điểm nhập C

điểm vào C thường được gọi là main (). nhưng một số công cụ xem main () và thêm rác vào mã của bạn. Tôi cố ý sử dụng một tên khác. YMMV.

bản sao của .data là không cần thiết nếu đây là tất cả dựa trên ram. là một vi điều khiển cortex-m về mặt kỹ thuật là có thể nhưng không thể vì vậy cần có bản sao .data ..... nếu có .data.

Ví dụ đầu tiên của tôi và một phong cách mã hóa là không dựa vào .data cũng như .bss, như trong ví dụ này. Arm đã chăm sóc con trỏ ngăn xếp nên điều duy nhất còn lại là gọi điểm vào. Tôi muốn có nó để điểm vào có thể trở lại, nhiều người tranh luận bạn không bao giờ nên làm điều đó. bạn chỉ có thể làm điều này sau đó:

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word centry
.word done
.word done
.word done

và không trả về từ centry () và không có mã xử lý thiết lập lại.

00000020 <centry>:
  20:   2207        movs    r2, #7
  22:   b510        push    {r4, lr}
  24:   4b04        ldr r3, [pc, #16]   ; (38 <centry+0x18>)
  26:   2007        movs    r0, #7
  28:   601a        str r2, [r3, #0]
  2a:   f7ff fff7   bl  1c <bounce>
  2e:   2000        movs    r0, #0
  30:   bc10        pop {r4}
  32:   bc02        pop {r1}
  34:   4708        bx  r1
  36:   46c0        nop         ; (mov r8, r8)
  38:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000

Trình liên kết đã đặt những thứ mà chúng tôi yêu cầu. Và tổng thể chúng tôi có một chương trình đầy đủ chức năng.

Vì vậy, đầu tiên làm việc trên kịch bản liên kết:

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

nhấn mạnh rằng tên rom và ram không có nghĩa là chúng chỉ kết nối các dấu chấm cho trình liên kết giữa các phần.

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:
    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    bx lr

.align
.word __data_rom_start__
.word __data_start__
.word __data_end__
.word __data_size__

thêm một số mục để chúng ta có thể thấy những gì các công cụ đã làm

void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

thêm một số mặt hàng để đặt trong những phần đó. và lấy

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000001b    andeq   r0, r0, r11, lsl r0
   c:   0000001b    andeq   r0, r0, r11, lsl r0
  10:   0000001b    andeq   r0, r0, r11, lsl r0

00000014 <reset>:
  14:   f000 f80c   bl  30 <centry>
  18:   e7ff        b.n 1a <done>

0000001a <done>:
  1a:   e7fe        b.n 1a <done>

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

00000030 <centry>:
  30:   2207        movs    r2, #7
  32:   b510        push    {r4, lr}
  34:   4b04        ldr r3, [pc, #16]   ; (48 <centry+0x18>)
  36:   2007        movs    r0, #7
  38:   601a        str r2, [r3, #0]
  3a:   f7ff ffef   bl  1c <bounce>
  3e:   2000        movs    r0, #0
  40:   bc10        pop {r4}
  42:   bc02        pop {r1}
  44:   4708        bx  r1
  46:   46c0        nop         ; (mov r8, r8)
  48:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

đây là thứ chúng tôi đang tìm kiếm trong thử nghiệm đó (lưu ý không có lý do để thực sự tải cũng như chạy bất kỳ mã nào ... biết công cụ của bạn, tìm hiểu chúng)

  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

Vì vậy, những gì chúng ta học được ở đây là vị trí của các biến rất nhạy cảm trong các tập lệnh liên kết gnu. lưu ý vị trí của data_rom_start so với data_start nhưng tại sao data_end hoạt động? Ill cho phép bạn tìm ra điều đó. Đã hiểu lý do tại sao người ta có thể không muốn phải lộn xộn với các tập lệnh liên kết và chỉ cần lập trình đơn giản ...

Vì vậy, một điều khác mà chúng tôi đã học được ở đây là trình liên kết được căn chỉnh data_rom_start cho chúng tôi, chúng tôi không cần ALIGN (4) trong đó. Chúng ta có nên cho rằng điều đó sẽ luôn luôn làm việc?

Cũng lưu ý rằng nó được đệm trên đường ra, chúng ta có 5 byte .data nhưng nó được đệm đến 8. Nếu không có bất kỳ ALIGN () nào, chúng ta có thể thực hiện sao chép bằng các từ. Dựa trên những gì chúng ta thấy với chuỗi công cụ này trên máy tính của tôi ngày hôm nay, điều đó có thể đúng với quá khứ và tương lai không? Ai biết được, ngay cả với các ALIGN cần kiểm tra định kỳ để xác nhận một số phiên bản mới không phá vỡ mọi thứ, họ sẽ làm điều đó theo thời gian.

từ thí nghiệm đó cho phép chuyển sang điều này chỉ để an toàn.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   . = ALIGN(4);
   __data_end__ = .;
   } > ted AT > bob
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   . = ALIGN(4);
   __bss_end__ = .;
   } > ted
   __bss_size__ = __bss_end__ - __bss_start__;

}

di chuyển các kết thúc bên trong để phù hợp với những gì người khác làm. Và điều đó đã không thay đổi nó:

0000001c <bounce>:
  1c:   4770        bx  lr
  1e:   46c0        nop         ; (mov r8, r8)
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

thêm một bài kiểm tra nhanh:

.globl bounce
bounce:
    nop
    bx lr

cho

0000001c <bounce>:
  1c:   46c0        nop         ; (mov r8, r8)
  1e:   4770        bx  lr
  20:   0000004c    andeq   r0, r0, r12, asr #32
  24:   20000000    andcs   r0, r0, r0
  28:   20000008    andcs   r0, r0, r8
  2c:   00000008    andeq   r0, r0, r8

không cần phải đệm giữa nảy và .align

Ồ, phải rồi, tôi nhớ tại sao tôi không đặt _end__ vào trong. bởi vì nó LÀM VIỆC.

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(4);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

   . = ALIGN(4);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

}

một số mã đơn giản nhưng rất dễ mang theo để kết hợp với tập lệnh liên kết này

.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
bss_zero:
    stmia r1!,{r2}
    sub r0,#4
    bne bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3}
    stmia r2!,{r3}
    sub r0,#4
    bne data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__

cho

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   0000003d    andeq   r0, r0, sp, lsr r0
   c:   0000003d    andeq   r0, r0, sp, lsr r0
  10:   0000003d    andeq   r0, r0, sp, lsr r0

00000014 <reset>:
  14:   480c        ldr r0, [pc, #48]   ; (48 <blen>)
  16:   2800        cmp r0, #0
  18:   d004        beq.n   24 <bss_zero_done>
  1a:   490a        ldr r1, [pc, #40]   ; (44 <bstart>)
  1c:   2200        movs    r2, #0

0000001e <bss_zero>:
  1e:   c104        stmia   r1!, {r2}
  20:   3804        subs    r0, #4
  22:   d1fc        bne.n   1e <bss_zero>

00000024 <bss_zero_done>:
  24:   480b        ldr r0, [pc, #44]   ; (54 <dlen>)
  26:   2800        cmp r0, #0
  28:   d005        beq.n   36 <data_copy_done>
  2a:   4908        ldr r1, [pc, #32]   ; (4c <rstart>)
  2c:   4a08        ldr r2, [pc, #32]   ; (50 <dstart>)

0000002e <data_copy>:
  2e:   c908        ldmia   r1!, {r3}
  30:   c208        stmia   r2!, {r3}
  32:   3804        subs    r0, #4
  34:   d1fb        bne.n   2e <data_copy>

00000036 <data_copy_done>:
  36:   f000 f80f   bl  58 <centry>
  3a:   e7ff        b.n 3c <done>

0000003c <done>:
  3c:   e7fe        b.n 3c <done>

0000003e <bounce>:
  3e:   46c0        nop         ; (mov r8, r8)
  40:   4770        bx  lr
  42:   46c0        nop         ; (mov r8, r8)

00000044 <bstart>:
  44:   20000008    andcs   r0, r0, r8

00000048 <blen>:
  48:   00000004    andeq   r0, r0, r4

0000004c <rstart>:
  4c:   00000074    andeq   r0, r0, r4, ror r0

00000050 <dstart>:
  50:   20000000    andcs   r0, r0, r0

00000054 <dlen>:
  54:   00000008    andeq   r0, r0, r8

00000058 <centry>:
  58:   2207        movs    r2, #7
  5a:   b510        push    {r4, lr}
  5c:   4b04        ldr r3, [pc, #16]   ; (70 <centry+0x18>)
  5e:   2007        movs    r0, #7
  60:   601a        str r2, [r3, #0]
  62:   f7ff ffec   bl  3e <bounce>
  66:   2000        movs    r0, #0
  68:   bc10        pop {r4}
  6a:   bc02        pop {r1}
  6c:   4708        bx  r1
  6e:   46c0        nop         ; (mov r8, r8)
  70:   20000008    andcs   r0, r0, r8

Disassembly of section .data:

20000000 <c>:
20000000:   00000005    andeq   r0, r0, r5

20000004 <b>:
20000004:   00000004    andeq   r0, r0, r4

Disassembly of section .bss:

20000008 <a>:
20000008:   00000000    andeq   r0, r0, r0

chúng ta có thể dừng lại ở đó hoặc tiếp tục đi. Nếu chúng ta khởi tạo theo thứ tự giống như tập lệnh liên kết thì không sao nếu chúng ta chuyển sang điều tiếp theo vì chúng ta chưa đến đó. và stm / ldm chỉ được yêu cầu / mong muốn sử dụng địa chỉ căn chỉnh từ, vì vậy nếu bạn thay đổi thành:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

với bss đầu tiên trong tập lệnh liên kết, và có bạn muốn ble không bls.

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3804        subs    r0, #4
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000004    andcs   r0, r0, r4

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

những vòng lặp sẽ đi nhanh hơn. bây giờ tôi không biết các bus ahb có thể rộng 64 bit hay không nhưng với một cánh tay có kích thước đầy đủ, bạn sẽ muốn căn chỉnh những thứ này trên ranh giới 64 bit. bốn thanh ghi ldm / stm trên ranh giới 32 bit nhưng không phải ranh giới 64 bit trở thành ba giao dịch xe buýt riêng biệt, trong đó căn chỉnh trên ranh giới 64 bit là một giao dịch duy nhất tiết kiệm nhiều đồng hồ trên mỗi lệnh.

vì chúng tôi đang thực hiện bar baral và chúng tôi chịu trách nhiệm hoàn toàn cho tất cả mọi thứ chúng tôi có thể nói bss trước sau đó là dữ liệu sau đó nếu chúng tôi có đống đó, thì stack sẽ tăng từ trên xuống, vì vậy nếu chúng tôi không bss và tràn vào chừng nào chúng tôi bắt đầu đúng nơi tốt là chúng tôi chưa sử dụng bộ nhớ đó. sau đó chúng tôi sao chép .data và có thể tràn vào heap đó là tốt, heap hay không có nhiều chỗ cho stack để chúng tôi không giẫm lên bất cứ ai / bất cứ điều gì (miễn là chúng tôi chắc chắn trong kịch bản liên kết chúng tôi làm điều đó. nếu có một mối quan tâm làm cho ALIGN () lớn hơn để chúng ta luôn nằm trong không gian của chúng ta cho những lần lấp đầy này.

Vì vậy, giải pháp đơn giản của tôi, mang nó hoặc để lại nó. hoan nghênh sửa bất kỳ lỗi nào, tôi không chạy nó trên phần cứng cũng như trình giả lập của mình ...

MEMORY
{
    bob : ORIGIN = 0x00000000, LENGTH = 0x1000
    ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > bob

    .rodata : { *(.rodata*) } > bob

   . = ALIGN(8);
   .bss  : {
   __bss_start__ = .;
   *(.bss*)
   } > ted
   . = ALIGN(4);
   __bss_end__ = .;
   __bss_size__ = __bss_end__ - __bss_start__;

   . = ALIGN(8);
   __data_rom_start__ = .;
   .data : {
    __data_start__ = .;
    *(.data*)
   } > ted AT > bob
   . = ALIGN(4);
   __data_end__ = .;
   __data_size__ = __data_end__ - __data_start__;

}



.thumb

.thumb_func
.global _start
_start:
stacktop: .word 0x20000800
.word reset
.word done
.word done
.word done

.thumb_func
reset:

    ldr r0,blen
    cmp r0,#0
    beq bss_zero_done
    ldr r1,bstart
    mov r2,#0
    mov r3,#0
    mov r4,#0
    mov r5,#0
bss_zero:
    stmia r1!,{r2,r3,r4,r5}
    sub r0,#16
    ble bss_zero
bss_zero_done:

    ldr r0,dlen
    cmp r0,#0
    beq data_copy_done
    ldr r1,rstart
    ldr r2,dstart
data_copy:
    ldmia r1!,{r3,r4,r5,r6}
    stmia r2!,{r3,r4,r5,r6}
    sub r0,#16
    ble data_copy
data_copy_done:

    bl centry
    b done

.thumb_func
done:   b .

.thumb_func
.globl bounce
bounce:
    nop
    bx lr

.align
bstart: .word __bss_start__
blen:   .word __bss_size__
rstart: .word __data_rom_start__
dstart: .word __data_start__
dlen:   .word __data_size__


void bounce ( unsigned int );

unsigned int a;

unsigned int b=4;
unsigned char c=5;

int centry ( void )
{
    a = 7;
    bounce(a);
    return(0);
}

arm-none-eabi-as --warn --fatal-warnings flash.s -o flash.o
arm-none-eabi-ld -o hello.elf -T flash.ld flash.o centry.o
arm-none-eabi-objdump -D hello.elf > hello.list
arm-none-eabi-objcopy hello.elf hello.bin -O binary

đặt tất cả lại với nhau và bạn nhận được:

Disassembly of section .text:

00000000 <_start>:
   0:   20000800    andcs   r0, r0, r0, lsl #16
   4:   00000015    andeq   r0, r0, r5, lsl r0
   8:   00000043    andeq   r0, r0, r3, asr #32
   c:   00000043    andeq   r0, r0, r3, asr #32
  10:   00000043    andeq   r0, r0, r3, asr #32

00000014 <reset>:
  14:   480d        ldr r0, [pc, #52]   ; (4c <blen>)
  16:   2800        cmp r0, #0
  18:   d007        beq.n   2a <bss_zero_done>
  1a:   490b        ldr r1, [pc, #44]   ; (48 <bstart>)
  1c:   2200        movs    r2, #0
  1e:   2300        movs    r3, #0
  20:   2400        movs    r4, #0
  22:   2500        movs    r5, #0

00000024 <bss_zero>:
  24:   c13c        stmia   r1!, {r2, r3, r4, r5}
  26:   3810        subs    r0, #16
  28:   ddfc        ble.n   24 <bss_zero>

0000002a <bss_zero_done>:
  2a:   480b        ldr r0, [pc, #44]   ; (58 <dlen>)
  2c:   2800        cmp r0, #0
  2e:   d005        beq.n   3c <data_copy_done>
  30:   4907        ldr r1, [pc, #28]   ; (50 <rstart>)
  32:   4a08        ldr r2, [pc, #32]   ; (54 <dstart>)

00000034 <data_copy>:
  34:   c978        ldmia   r1!, {r3, r4, r5, r6}
  36:   c278        stmia   r2!, {r3, r4, r5, r6}
  38:   3810        subs    r0, #16
  3a:   ddfb        ble.n   34 <data_copy>

0000003c <data_copy_done>:
  3c:   f000 f80e   bl  5c <centry>
  40:   e7ff        b.n 42 <done>

00000042 <done>:
  42:   e7fe        b.n 42 <done>

00000044 <bounce>:
  44:   46c0        nop         ; (mov r8, r8)
  46:   4770        bx  lr

00000048 <bstart>:
  48:   20000000    andcs   r0, r0, r0

0000004c <blen>:
  4c:   00000004    andeq   r0, r0, r4

00000050 <rstart>:
  50:   20000008    andcs   r0, r0, r8

00000054 <dstart>:
  54:   20000004    andcs   r0, r0, r4

00000058 <dlen>:
  58:   00000008    andeq   r0, r0, r8

0000005c <centry>:
  5c:   2207        movs    r2, #7
  5e:   b510        push    {r4, lr}
  60:   4b04        ldr r3, [pc, #16]   ; (74 <centry+0x18>)
  62:   2007        movs    r0, #7
  64:   601a        str r2, [r3, #0]
  66:   f7ff ffed   bl  44 <bounce>
  6a:   2000        movs    r0, #0
  6c:   bc10        pop {r4}
  6e:   bc02        pop {r1}
  70:   4708        bx  r1
  72:   46c0        nop         ; (mov r8, r8)
  74:   20000000    andcs   r0, r0, r0

Disassembly of section .bss:

20000000 <a>:
20000000:   00000000    andeq   r0, r0, r0

Disassembly of section .data:

20000004 <c>:
20000004:   00000005    andeq   r0, r0, r5

20000008 <b>:
20000008:   00000004    andeq   r0, r0, r4

lưu ý rằng điều này hoạt động với arm-none-eabi- và arm-linux-gnueabi và các biến thể khác vì không có công cụ ghee whiz nào được sử dụng.

Bạn sẽ thấy khi bạn nhìn xung quanh rằng mọi người sẽ phát điên với những thứ ghee whiz trong các tập lệnh liên kết của họ, những thứ nhà bếp khổng lồ quái dị. Tốt hơn là chỉ biết làm thế nào để làm điều đó (hoặc tốt hơn là làm chủ các công cụ để bạn có thể kiểm soát những gì đang diễn ra) thay vì dựa vào công cụ của ai đó và không biết nó sẽ bị phá vỡ ở đâu vì bạn không hiểu và / hoặc muốn nghiên cứu nó

như một quy tắc chung, đừng bootstrap một ngôn ngữ có cùng ngôn ngữ (bootstrap theo nghĩa này có nghĩa là chạy mã không biên dịch một trình biên dịch với cùng một trình biên dịch), bạn muốn sử dụng một ngôn ngữ đơn giản hơn với ít bootstrap hơn. Đó là lý do tại sao C được thực hiện trong lắp ráp, nó không có yêu cầu bootstrap mà bạn chỉ bắt đầu từ hướng dẫn đầu tiên sau khi thiết lập lại. JAVA, chắc chắn bạn có thể viết jvm bằng C và bootstrap mà C bằng asm sau đó bootstrap JAVA nếu bạn muốn với C nhưng cũng thực hiện JAVA trong C nữa.

Bởi vì chúng tôi kiểm soát các giả định trên các vòng lặp sao chép này, theo định nghĩa chặt chẽ và sạch sẽ hơn so với memcpy / memset điều chỉnh bằng tay.

Lưu ý vấn đề khác của bạn là đây:

unsigned int * bss_start_p = &_BSS_START; 
unsigned int * bss_end_p = &_BSS_END;

Nếu đây là tiền phạt cục bộ, không có vấn đề gì, nếu đây là toàn cục thì bạn cần .data khởi tạo trước để chúng hoạt động và nếu bạn thử mẹo đó để làm .data thì bạn sẽ thất bại. Biến cục bộ, tốt mà sẽ làm việc. nếu bạn vì một lý do nào đó quyết định thực hiện các địa phương tĩnh (toàn cầu địa phương tôi muốn gọi cho họ) thì bạn sẽ lại gặp rắc rối. Mỗi khi bạn thực hiện một nhiệm vụ trong một tuyên bố mặc dù bạn nên nghĩ về nó, nó được thực hiện như thế nào và nó có an toàn / lành mạnh không. Mỗi khi bạn giả sử một biến là 0 khi không được khai báo, cùng một giao dịch, nếu một biến cục bộ thì nó không được coi là 0, nếu là toàn cục thì nó là. nếu bạn không bao giờ cho rằng chúng bằng 0 thì bạn không bao giờ phải lo lắng.


thật tuyệt vời, đây là lần thứ hai tôi vượt quá số lượng ký tự tối đa trong một câu trả lời ....
old_timer

Câu hỏi này thuộc về stackoverflow không phải kỹ thuật điện.
old_timer

Cũng dựa vào một liên kết bên ngoài trong câu hỏi của bạn không phải là hình thức tốt, nếu liên kết biến mất trước câu hỏi thì câu hỏi có thể không có ý nghĩa.
old_timer

Trong trường hợp này, tiêu đề và nội dung của bạn đủ để biết rằng bạn đang cố gắng khởi động C trên một vi điều khiển cụ thể và đang lang thang vào .bss và khởi tạo .data
old_timer

nhưng trong trường hợp này đã bị đánh lừa bởi một trang web rất nhiều thông tin.
old_timer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.