Cortex M3 .bss 영역 초기화를위한 베어 메탈 시작 코드


10

난에서 영감을 개발 한 여기 팔 외피 M3를위한 베어 메탈 시작 코드. 그러나 다음과 같은 문제가 발생합니다. main.c의 unsigned char 유형과 같이 초기화되지 않은 전역 변수를 선언한다고 가정하십시오.

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

그러면 STM32 f103의 .bss 영역이 _BSS_START = 0x20000000에서 시작하여 _BSS_END = 0x20000001에서 끝납니다. 이제 시작 코드

    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++;
    }

전체 .bss 영역을 0으로 초기화하려고 시도합니다. 그러나 while 루프 내에서 포인터는 4 바이트로 증가하므로 한 단계 bss_start_p = 0x20000004 후에는 항상 bss_end_p와 달라 무한 루프 등이 발생합니다.

이것에 대한 표준 솔루션이 있습니까? 어떻게 든 .bss 영역의 크기를 4의 배수로 "강제"한다고 가정합니까? 또는 부호없는 char에 대한 포인터를 사용하여 .bss 영역을 통과해야합니까? 아마도 다음과 같습니다.

    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++;
    }
```

보다 적게 사용하십시오. 부트 스트랩은 이유 때문에 어셈블리로 작성됩니다. 먼저 .data 문제가 발생했습니다. C가 작동하는 닭고기와 계란은 최소한 .text, .bss 및 .data에 의존한다고 가정하지만 C 코드가 필요한 C 코드를 사용하여 C 코드가 작동하도록하는 C 코드를 작성하고 있습니다. C 작업에 의존하는 C 코드로 작성된 부트 스트랩.
old_timer

.data를 복사하는 코드는 .bss와 매우 유사하지만 위의 코드와 같이 작성하면 .data를 복사하려면 .data를 복사해야합니다.
old_timer

답변:


15

알 수 있듯이 부호없는 int 데이터 형식의 크기가 4 바이트이기 때문에 이런 일이 발생합니다. 각 *bss_start_p = 0;명령문은 실제로 bss 영역의 4 바이트를 지 웁니다.

bss 메모리 범위가 올바르게 정렬되어야합니다. 총 크기가 4의 배수가되도록 _BSS_START 및 _BSS_END를 간단하게 정의 할 수 있지만 일반적으로 링커 스크립트가 시작 및 중지 위치를 정의 할 수 있도록 처리됩니다.

예를 들어 다음은 내 프로젝트 중 하나의 링커 섹션입니다.

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

ALIGN(4)문 것들을주의해야합니다.

또한 변경하고 싶을 수도 있습니다

while(bss_start_p != bss_end_p)

while(bss_start_p < bss_end_p).

이렇게해도 문제를 예방할 수는 없지만 (원하는 것보다 1 ~ 3 바이트 더 많은 바이트를 지우면) 영향을 최소화 할 수 있습니다.


@ CMarius 반영하면 더 많은 사이클이 필요하지만 char 포인터 아이디어가 훌륭하게 작동한다고 생각합니다. 그러나 다음 메모리 영역에 정렬되지 않은 후속 문제가 있는지 확실하지 않으므로 답변에서 언급하지 않을 것입니다.
bitsmack

1
while(bss_start_p < bss_end_p - 1)나머지 메모리 범위를 바이트 단위로 지우면 마지막 문제가 해결됩니다.
glglgl

4

표준 솔루션은 memset()다음과 같습니다.

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

표준 라이브러리를 사용할 수 없다면 메모리 영역의 크기를 최대 4 바이트로 반올림하고 계속 사용하는 것이 좋은지 결정해야합니다 unsigned int *. 또는 엄격해야하는 경우을 사용해야 unsigned char *합니다.

첫 번째 루프에서와 같이 크기를 반올림하면 bss_start_p실제로는 결국보다 크지 bss_end_p<부등식 테스트 대신 비교하기가 쉽지 않습니다 .

물론 대부분의 메모리 영역을 32 비트 전송으로 채울 수 있으며 마지막 몇 바이트 만 8 비트 전송으로 채울 수 있지만, 특히 시작 코드 부분 일 때 적은 이득을 얻기 위해 더 많은 작업이 필요합니다.


1
의 사용에 매우 동의합니다 memset(). 그러나 4 바이트로 정렬하는 것은 필수입니다. 왜 안 해?
Codo

3
부트 스트랩이 memset을 사용하는 표준 솔루션은 모양이나 형태가 결코 아닙니다.
old_timer

같은 언어를 사용하여 해당 언어를 부트 스트랩하지 마십시오
old_timer

2
부트 스트랩 코드와 링커 스크립트는 매우 결혼했습니다. 링커 스크립트는 적어도 4 바이트 경계에서 .bss를 정렬하고 크기를 조정하여 한 번에 바이트 단위로 채우기 (부트 스트랩에서)를 4 배 향상시킵니다. (암에 일반적이지만 예외가있는 32 비트 버스를 가정 (최소))
old_timer

3
@old_timer, 메모리를 특정 값으로 설정하는 표준 C 함수는입니다 memset(). C는 프로그래밍중인 것으로 보입니다. 간단한 구현 memset()도 해당 루프와 거의 비슷하지만 다른 것에 의존하는 것과는 다릅니다. 그것은 마이크로 컨트롤러이기 때문에 동적 링크가 없거나 계속 진행되고 있다고 가정합니다 (그리고 링크를보고, main()제로 루프를 호출 한 것이 아니라고 가정). 그래서 컴파일러는 memset()거기 에 빠질 수 있어야합니다 다른 기능과 함께 (또는 인라인으로 구현).
ilkkachu

4

로 변경 !=하십시오 <. 어쨌든 이런 문제를 다루기 때문에 일반적으로 더 나은 접근 방식입니다.


3

수많은 다른 사이트와 예제가 있습니다. 수만이 아니라면 수천명. 링커 스크립트와 부 스트랩 코드, 특히 newlib, glibc가있는 잘 알려진 c 라이브러리가 있지만 찾을 수있는 다른 라이브러리가 있습니다. C를 C로 부트 스트래핑하는 것은 의미가 없습니다.

귀하의 질문에 귀하는 정확하지 않을 수있는 것들에 대해 정확하게 비교하려고 노력하고 있으며, 알려진 경계에서 시작하지 않거나 알려진 경계에서 끝날 수 있습니다. 따라서보다 적은 일을 할 수 있지만 코드가 정확한 비교로 작동하지 않으면 나쁜 일이 발생하거나 발생하지 않을 수있는 다음 섹션으로 .bss를 제로화하고 있음을 의미합니다. 해결책.

여기에 TL이 있습니다 .DR은 좋습니다. 당신은 그 언어로 언어를 부트 스트랩하지 않습니다, 당신은 그것을 확실히 벗어날 수 있지만, 그렇게 할 때 불을 가지고 놀고 있습니다. 이 작업을 수행하는 방법을 배우는 경우 아직 멍청한 운이나 사실을 밝히지 말고 조심해야합니다.

링커 스크립트와 부트 스트랩 코드는 매우 친밀한 관계를 맺고 있으며 결혼하고 엉덩이에 합류하여 대규모 실패로 이어질 수 있습니다. 불행히도 링커 스크립트는 링커와 어셈블러에서 정의한 어셈블리 언어로 정의되므로 툴체인을 변경하면 두 언어를 모두 다시 작성해야합니다. 왜 어셈블리 언어입니까? 부트 스트랩이 필요 없으며 일반적으로 컴파일 된 언어가 필요합니다. C는 언어의 사용을 제한하지 않으려면 툴 체인 특정 요구 사항이 최소 인 매우 간단한 것으로 시작합니다. .bss 변수가 0이라고 가정하지 마십시오 (변수가 해당 언어로 초기화되지 않으면 코드를 읽기 어렵게 만듭니다) , 이것을 피하려고 노력하십시오, 지역 변수에 대해서는 사실이 아니므로 그것을 사용할 때 공에 있어야합니다. 왜 우리는 .bss와 .data에 대해 이야기하고 있습니까? (글로벌은이 레벨 작업에는 좋지만 다른 주제입니다) 간단한 솔루션의 다른 규칙은 선언에서 변수를 초기화하지 말고 코드에서 수행하는 것입니다. 예, 더 많은 플래시를 태우십시오. 일반적으로 많은 변수가 있습니다. 어쨌든 모든 변수가 상수를 사용하여 초기화되지는 않아 결국 명령을 소비하게됩니다.

cortex-m 디자인에서 부트 스트랩 코드가 전혀 없다고 생각했을 수 있으므로 .data 또는 .bss 지원이 없음을 알 수 있습니다. 글로벌을 사용하는 대부분의 사람들은 그렇게하지 않으면 살 수 없습니다.

gnu 툴체인을 사용하여 모든 피질-ms에 대해이 최소보다 작지만 기능적인 예를 만들 수 있습니다. 현재 9.xx에서 링커 스크립트를 전환 한 현재 9.xx를 통해 5.xx 이상으로 시작할 수있는 버전을 기억하지 못합니다. xx 또는 4.xx는 더 많은 것을 배우고 gnu가 내 첫 것을 깨뜨린 것을 바꿨습니다.

부트 스트랩 :

.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

C 코드의 진입 점 :

void bounce ( unsigned int );

unsigned int a;

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

링커 스크립트.

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

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

이 모든 것이 더 작고 여전히 작동 할 수 있습니다. 직장에서 볼 수 있도록 여기에 추가 자료를 추가했습니다.

최적화 된 빌드 및 링크.

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

일부 공급 업체의 경우 플래시가 매핑되어 일부 부팅 모드에서 0x00000000에 미러링 될 때 0x08000000 또는 0x01000000 또는 기타 유사한 주소를 사용하려고합니다. 일부는 0x00000000에 너무 많은 플래시를 미러링하기 때문에 벡터 테이블 포인트를 응용 프로그램 플래시 공간에서 0이 아닌 것으로 지정하려고합니다. 그것은 벡터 테이블 기반이기 때문에 모든 것이 작동합니다.

첫 번째로 cortex-ms는 Thumb 전용 시스템이며 어떤 이유로 든 Thumb 기능 주소를 적용했기 때문에 lsbit가 홀수임을 의미합니다. 도구를 알고 .thumb_func 지시문은 gnu 어셈블러에 다음 레이블이 썸 함수 주소임을 알려줍니다. 테이블에서 +1을 수행하면 실패로 이어질 수 있습니다. 함수를 선언하는 다른 gnu 어셈블러 방법이 있습니다. 이것은 최소한의 접근법입니다.

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

벡터 테이블을 제대로 얻지 못하면 부팅되지 않습니다.

스택 포인터 벡터 (스택 포인터를 코드로 직접 설정하려면 아무것도 넣을 수 있음)와 재설정 벡터 만 있으면됩니다. 특별한 이유없이 여기에 4 개를 넣었습니다. 일반적으로 16을 넣지 만이 예를 줄이려고했습니다.

그렇다면 C 부트 스트랩이 수행해야하는 최소한의 작업은 무엇입니까? 1. 스택 포인터를 설정합니다. 2. .bss 제로 3. .data 복사 4. 분기점 또는 C 진입 점 호출

C 진입 점은 일반적으로 main ()이라고합니다. 그러나 일부 툴체인은 main ()을보고 코드에 가비지를 추가합니다. 나는 의도적으로 다른 이름을 사용합니다. YMMV.

이것이 램 기반이라면 .data의 사본은 필요하지 않습니다. cortex-m 마이크로 컨트롤러이기 때문에 기술적으로 가능하지만 .data가 있으면 .data 사본이 필요합니다.

첫 번째 예와 코딩 스타일은이 예와 같이 .data 나 .bss에 의존하지 않는 것입니다. Arm은 스택 포인터를 처리하여 남은 것은 진입 점을 호출하는 것입니다. 진입 점이 돌아올 수 있기를 원합니다. 많은 사람들은 당신이 그렇게해서는 안된다고 주장합니다. 당신은 이것을 할 수 있습니다 :

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

centry ()에서 반환되지 않으며 리셋 처리기 코드가 없습니다.

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

링커는 우리가 요구 한 것을 넣었습니다. 그리고 전체적으로 우리는 완전한 기능을 갖춘 프로그램을 가지고 있습니다.

먼저 링커 스크립트를 작성하십시오.

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__;

}

rom과 ram이라는 이름은 섹션 사이의 링커 점만 연결한다는 의미는 없습니다.

.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__

도구가 수행 한 작업을 볼 수 있도록 몇 가지 항목을 추가하십시오.

void bounce ( unsigned int );

unsigned int a;

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

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

해당 섹션에 배치 할 항목을 추가하십시오. 그리고 얻다

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

여기 우리가 실험에서 찾고있는 것들이 있습니다 (실제로 코드를로드하거나 실행할 이유가 없습니다 ... 도구를 알고 배우십시오)

  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

여기서 배운 것은 gnu 링커 스크립트에서 변수의 위치가 매우 민감하다는 것입니다. 의 위치에 유의 data_rom_startdata_start을 하지만 왜하지 data_end의 일을? 내가 알아낼 게 링커 스크립트를 망쳐 놓고 간단한 프로그래밍을 원하지 않는 이유를 이미 이해하고 있습니다 ...

우리가 여기서 배운 또 다른 것은 링커가 data_rom_start 를 정렬 하여 거기에 ALIGN (4)이 필요 없다는 것입니다. 우리는 그것이 항상 효과가 있다고 가정해야합니까?

또한 도중에 채워지는 5 바이트의 .data가 있지만 8로 채워졌습니다. ALIGN ()이 없으면 단어를 사용하여 이미 복사 할 수 있습니다. 오늘날 내 컴퓨터에서이 툴체인으로 볼 수있는 내용을 토대로 과거와 미래에 해당 될 수 있습니까? ALIGN이 있어도 일부 새 버전에서 문제가 발생하지 않았 음을 확인하기 위해 정기적으로 확인해야하는 경우가 있습니다.

그 실험으로부터 안전을 위해 이것으로 넘어갑니다.

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__;

}

다른 사람들이하는 것과 일치하도록 끝을 안으로 옮기는 것. 그리고 그것은 그것을 바꾸지 않았습니다.

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

하나 더 빠른 테스트 :

.globl bounce
bounce:
    nop
    bx lr

기부

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

바운스와 .align 사이를 채울 필요가 없습니다.

아, _end__를 넣지 않은 이유를 기억합니다. 작동하지 않기 때문입니다.

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__;

}

이 링커 스크립트와 결혼하는 간단하지만 이식성이 뛰어난 코드

.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__

기부

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

우리는 거기서 멈추거나 계속 갈 수 있습니다. 링커 스크립트와 같은 순서로 초기화하면 아직 얻지 않은 다음 항목으로 넘어가도 괜찮습니다. stm / ldm은 단어로 정렬 된 주소 만 사용하도록 요구 / 원하는 것이므로 다음과 같이 변경하면

    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:

링커 스크립트에서 먼저 bss를 사용하면 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

루프가 더 빨라집니다. 이제 ahb 버스가 64 비트 너비인지 아닌지 알 수 없지만 전체 크기의 팔의 경우 64 비트 경계에서 이러한 것을 정렬하려고합니다. 32 비트 경계에 있지만 64 비트 경계에 있지 않은 4 개의 레지스터 ldm / stm은 3 개의 개별 버스 트랜잭션이됩니다. 여기서 64 비트 경계에 정렬 된 것은 단일 트랜잭션으로 명령 당 여러 클럭을 저장합니다.

우리가 베어 메탈을 수행하고 있기 때문에 우리는 먼저 bss라고 말한 다음 데이터를 넣을 수있는 모든 것에 대해 전적으로 책임을지고 있기 때문에 힙이 있다면 스택은 위에서 아래로 커집니다. 우리는 아직 그 메모리를 사용하고 있지 않은 올바른 장소입니다. 그런 다음 .data를 복사하고 힙에 쏟아 질 수 있습니다. 스택을위한 충분한 공간이 없거나 힙이 없어서 누군가 / 어떤 것도 밟지 않습니다 (링커 ​​스크립트에서 확인하는 한). 문제가 있으면 ALIGN ()을 더 크게 만들어서 항상 이러한 채우기를위한 공간 내에 영역을 두십시오.

내 간단한 해결책, 가져 가거나 떠나십시오. 버그를 수정 해 주셔서 감사합니다. 하드웨어 나 시뮬레이터에서 실행하지 않았습니다.

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

모두 합치면 다음과 같은 이점이 있습니다.

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

이것은 ghee whiz 재료가 사용되지 않았기 때문에 arm-none-eabi- 및 arm-linux-gnueabi 및 기타 변형에서 작동합니다.

주변 사람들을 둘러 보면 링커 스크립트의 거대한 휘슬 물건, 거대한 괴물 주방 싱크대에 미치게 될 것입니다. 다른 사람의 물건에 의존하지 않고 연구 방법을 아는 것 (또는 도구를 숙달하는 방법을 잘 익히는 것)을 이해하는 것이 좋으며, 연구를 이해하지 못하거나 연구하기를 원하기 때문에 부서 질 곳을 모릅니다. 그것.

일반적으로 동일한 언어로 언어를 부트 스트랩하지 마십시오 (이 의미에서 부트 스트랩은 동일한 컴파일러로 컴파일러를 컴파일하지 않고 코드를 실행한다는 의미) 부트 스트랩이 적은 간단한 언어를 사용하려고합니다. 그렇기 때문에 C는 어셈블리에서 수행되므로 재설정 후 첫 번째 명령에서 시작하는 부트 스트랩 요구 사항이 없습니다. JAVA, jvm을 C로 작성하고 asm으로 C를 부트 스트랩 한 다음 C로 할 경우 JAVA를 부트 스트랩하고 C에서도 JAVA를 실행하십시오.

우리는 이러한 카피 루프에 대한 가정을 제어하기 때문에 정의에 따라 수동으로 조정 된 memcpy / memset보다 더 단단하고 깨끗합니다.

다른 문제는 다음과 같습니다.

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

이것들이 로컬 괜찮고 문제가 없다면, 이것들이 전역 적이라면 먼저 작동하기 위해 .data를 초기화해야하며 .data를 수행하는 트릭을 시도하면 실패 할 것입니다. 로컬 변수, 잘 작동합니다. 만약 당신이 어떤 이유로 정적 지역을 만들기로 결정했다면 (로컬 전역을 호출하고 싶습니다) 다시 문제가 생깁니다. 선언에서 과제를 할 때마다 생각해야하지만 어떻게 구현되고 안전하고 안전합니까? 선언되지 않은 경우 변수가 0이라고 가정 할 때마다 로컬 변수가 0으로 가정되지 않은 경우 전역 변수 인 경우 로컬 변수입니다. 절대 0으로 가정하지 않으면 걱정할 필요가 없습니다.


굉장, 이것은 대답에서 최대 문자 수를 초과 한 두 번째 시간입니다 ....
old_timer

이 질문은 전기 공학이 아닌 스택 오버 플로우에 속합니다.
old_timer

또한 질문에서 외부 링크에 의존하는 것은 좋은 형태가 아닙니다. 질문 전에 링크가 사라지면 질문이 이해되지 않을 수 있습니다.
old_timer

이 경우 귀하의 제목과 내용이 특정 마이크로 컨트롤러에 C를 부트 스트랩을 시도하고 .bss라고하고 .DATA 초기화로 방황하는 것을 알고 충분하다
old_timer

그러나이 경우에는 매우 유익한 웹 사이트에서 오도되었습니다.
old_timer
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.