2017-09-12 9 views
1

stm32l152Cディスカバリボードのarm cortex-m3のCコードを実行していますが、メインからの関数呼び出しがスタックにプッシュされていないことがわかりました。私はこのソースのasmコードを分析しましたが、OKです。よりよく理解するために、ここではCコードを生成アセンブラコードを見てください。メインからのC関数がスタック内でスタックを押していない

main.elf:  file format elf32-littlearm 

*SYMBOL TABLE: 
00000010 l d .text 00000000 .text 
00000000 l d .debug_info 00000000 .debug_info 
00000000 l d .debug_abbrev 00000000 .debug_abbrev 
00000000 l d .debug_aranges 00000000 .debug_aranges 
00000000 l d .debug_line 00000000 .debug_line 
00000000 l d .debug_str 00000000 .debug_str 
00000000 l d .comment 00000000 .comment 
00000000 l d .ARM.attributes 00000000 .ARM.attributes 
00000000 l d .debug_frame 00000000 .debug_frame 
00000000 l df *ABS* 00000000 main.c 
00000000 l df *ABS* 00000000 clock.c 
20004ffc g  .text 00000000 _STACKTOP 
**00000028 g  F .text 000000e0 SystemClock_Config** 
20000000 g  .text 00000000 _DATA_BEGIN 
20000000 g  .text 00000000 _HEAP 
**00000010 g  F .text 00000016 main** 
20000000 g  .text 00000000 _BSS_END 
00000108 g  .text 00000000 _DATAI_BEGIN 
20000000 g  .text 00000000 _BSS_BEGIN 
00000108 g  .text 00000000 _DATAI_END 
20000000 g  .text 00000000 _DATA_END 
Disassembly of section .text: 
00000010 <main>: 

#define LL_GPIO_MODE_OUTPUT 1 

void SystemInit() ; 
int main() 
{ 
    10: b580  push {r7, lr} 
    12: b082  sub sp, #8 
    14: af00  add r7, sp, #0 
    int i = 0; 
    16: 2300  movs r3, #0 
    18: 607b  str r3, [r7, #4] 
    SystemClock_Config(); 
    **1a: f000 f805 bl 28 <SystemClock_Config> 
    for(;;) 
     i++; 
    1e: 687b  ldr r3, [r7, #4] 
    20: 3301  adds r3, #1** 
    22: 607b  str r3, [r7, #4] 
    24: e7fb  b.n 1e <main+0xe> 

} 
00000028 <SystemClock_Config>: 
    *   PLLDIV       = 3 
    *   Flash Latency(WS)    = 1 
    * @retval None 
    */ 
void SystemClock_Config(void) 
{ 
    28: b480  push {r7} 
    2a: af00  add r7, sp, #0 
    SET_BIT(FLASH->ACR, FLASH_ACR_ACC64); 
    2c: 4a33  ldr r2, [pc, #204] ; (fc <SystemClock_Config+0xd4>) 
    2e: 4b33  ldr r3, [pc, #204] ; (fc <SystemClock_Config+0xd4>) 
    30: 681b  ldr r3, [r3, #0] 
    32: f043 0304 orr.w r3, r3, #4 
    36: 6013  str r3, [r2, #0] 
    MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, LL_FLASH_LATENCY_1); 
    38: 4a30  ldr r2, [pc, #192] ; (fc <SystemClock_Config+0xd4>) 
    3a: 4b30  ldr r3, [pc, #192] ; (fc <SystemClock_Config+0xd4>) 
    3c: 681b  ldr r3, [r3, #0] 
    3e: f043 0301 orr.w r3, r3, #1 
    42: 6013  str r3, [r2, #0]* 
} 

実行は0x1a、0x1cに、0x1eが表示、PCレジスタに0x20の周りをループします。

halted: PC: 0x0000001a 
halted: PC: 0x0000001c 
halted: PC: 0x0000001e 
halted: PC: 0x00000020 
halted: PC: 0x0000001a 
halted: PC: 0x0000001c 
halted: PC: 0x0000001e 
halted: PC: 0x00000020 
halted: PC: 0x0000001a 
halted: PC: 0x0000001c 
halted: PC: 0x0000001e 
halted: PC: 0x00000020 

0x1aの0x28(SystemClock_Config)にジャンプする必要があります。

+1

probelemは何を使うのか?スタックをプッシュしないものは何ですか?パラメータ - 可能な場合はレジスタを介して渡されます。 'bl' - 関数を呼び出します。 –

+1

PS生成されたコードの解析を停止します。まず第一にそれを理解していないからです。第二に、コンパイラがコード生成に非常に優れているからです。生成されたコードが大丈夫であることを確かめることができます。何かがうまくいかない場合 - コンパイラではなくあなたのコードです –

+1

最適化を無効にしてコンパイルしているので、asmは醜く読みにくい(たくさんのストア/リロード)。少なくとも-Ogや-O1を使ってください。 –

答えて

1

アプリケーションに割り込みテーブルがありません。その結果、プロセッサは命令を割り込みベクタとして読み込み、その命令が無効なアドレスとして解釈されないため、繰り返しフォルトが発生します。

STM32L1xx standard peripheral libraryのサポートファイルを使用して、適切なリンカースクリプトと割り込みテーブルを生成します。

+0

私はそれを見ていませんが、アドレス0x00000000、0x00000004の値はありません。これらの値はすべてブートに必要です。 (技術的には0x00000004がすべて必要です)。メインは0x10から始まりますが、興味深いですが、起動成功のキーワードは表示されません。あなたが過去のリセットを取得した後に与えられた問題は他にもあるでしょう... –

+0

@old_timerリセットベクトルに明示的にデータが置かれていないのに、 'main'関数を指していない可能性があります。例えば、PCトレースに関係する '0x0000_001a'アドレスを指している可能性があります。 – duskwuff

+0

が理解されていますが、本当に何が起こっているのかを知るには十分な情報がありません。 –

3

非常に単純な完全実施例:

.thumb 

.globl _start 
_start: 

.word 0x20001000 
.word reset 

.thumb_func 
reset: 
    bl centry 
done: b done 

so.c

unsigned int fun (unsigned int); 
unsigned int centry (void) 
{ 
    return(fun(5)+1); 
} 

fun.c

unsigned int fun (unsigned int x) 
{ 
    return(x+1); 
} 

がをflash.ld

vectors.s

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

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

ビルド

arm-none-eabi-as --warn --fatal-warnings -mcpu=cortex-m0 vectors.s -o vectors.o 
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c so.c -o so.o 
arm-none-eabi-gcc -Wall -Werror -O2 -nostdlib -nostartfiles -ffreestanding -mcpu=cortex-m0 -mthumb -c fun.c -o fun.o 
arm-none-eabi-ld -o so.elf -T flash.ld vectors.o so.o fun.o 
arm-none-eabi-objdump -D so.elf > so.list 
arm-none-eabi-objcopy so.elf so.bin -O binary 

プログラム全体

00000000 <_start>: 
    0: 20001000 andcs r1, r0, r0 
    4: 00000009 andeq r0, r0, r9 

00000008 <reset>: 
    8: f000 f802 bl 10 <centry> 

0000000c <done>: 
    c: e7fe  b.n c <done> 
    ... 

00000010 <centry>: 
    10: b510  push {r4, lr} 
    12: 2005  movs r0, #5 
    14: f000 f802 bl 1c <fun> 
    18: 3001  adds r0, #1 
    1a: bd10  pop {r4, pc} 

0000001c <fun>: 
    1c: 3001  adds r0, #1 
    1e: 4770  bx lr 

プログラムのシミュレーション:

read32(0x00000000)=0x20001000 
read32(0x00000004)=0x00000009 
--- 0x00000008: 0xF000 
--- 0x0000000A: 0xF802 bl 0x0000000F 
--- 0x00000010: 0xB510 push {r4,lr} 
write32(0x20000FF8,0x00000000) 
write32(0x20000FFC,0x0000000D) 
--- 0x00000012: 0x2005 movs r0,#0x05 
--- 0x00000014: 0xF000 
--- 0x00000016: 0xF802 bl 0x0000001B 
--- 0x0000001C: 0x3001 adds r0,#0x01 
--- 0x0000001E: 0x4770 bx r14 
--- 0x00000018: 0x3001 adds r0,#0x01 
--- 0x0000001A: 0xBD10 pop {r4,pc} 
read32(0x20000FF8)=0x00000000 
read32(0x20000FFC)=0x0000000D 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 
--- 0x0000000C: 0xE7FE b 0x0000000B 

必ずそれが多少役に立たないプログラムですが、それが起動し、呼び出しを示してい関数(関数のアドレスは表示されませんスタック上では、呼び出しを行うと(bl)、r14は戻りアドレスを取得し、r15は分岐先のアドレスを取得します。セントリリーのようなネストされた関数がある場合(Cのエントリポイントmain()は重要な関数名ではありませんが、あなたのブートストラップがマッチしている限り、あなたのエントリーポイントを呼び出すことができます)funを呼び出すと、通常はスタックに保存します。 r4はスタックをabiごとに64ビット境界に整列させておくために押されています。

システムでは、通常0x08000000のリンカースクリプトを設定します(stm32)。

バイナリの始まりですが、mainの最初の数個の命令を含むmainの前に一握りのバイトを示すメモリイメージ/バイナリのhexdumpを実行できますか?

ベアメタルプログラムが最も簡単なブート手順を実行しない場合、最初に行うのは、エントリポイントまたはベクタテーブルがアーキテクチャに依存するバイナリを調べて、それを正しく構築したことを確認することです。

この例ではこれはcortex-mなので、スタックポインタの初期化値(使用する場合)は0x00000000になっていますので、何かを置いて、あなたの選択...アドレス0x00000004は、サムモードを示すようにlsbitでリセットを処理するコードのアドレスであるリセットベクトルです。

0x00000008 | 1 = 0x00000009です。あなたは

0x2000xxxx 0x00000011

を持っていけない場合

は、あなたのプロセッサが右起動するつもりはありません。私は、0x00000000がstmのために働くならば、私が覚えていない0x08000000を使う習慣がとてもあります。理論的には...しかし、フラッシュをどのようにロードしているのか、どのモード/チップがその時にあるのかによって異なります。

他に何もあなたのバイナリ/メモリイメージの最初の2つの単語として

0x2000xxxx 0x08000011

を変更しない場合は、0x08000000のため、最小でリンクする必要があります。

EDIT

ノートあなたは、ベクトルやスタックアドレスのスポットで(スペースを埋めるためにもBL)の枝を置くブートローダ

.thumb 

.thumb_func 
.global _start 
_start: 
bl reset 
.word _start 
reset: 
    ldr r0,stacktop 
    mov sp,r0 
    bl notmain 
    b hang 
.thumb_func 
hang: b . 
.align 
stacktop: .word 0x20001000 

との両方を入力することができ、単一のバイナリを作ることができますスタックポインタを後でロードします。

またはブランチ

.thumb 

.thumb_func 
.global _start 
_start: 
b reset 
nop 
.word _start 
reset: 
    ldr r0,stacktop 
    mov sp,r0 
    bl notmain 
    b hang 
.thumb_func 
hang: b . 
.align 
stacktop: .word 0x20001000 
+0

stm32ロジックは0x08000000から0x00000000にマッピングされ、アプリケーションプログラムが0x08000011をフラッシュするか、リセットベクトルが何であっても実際のアドレスに移動します。マイクロコントローラでブート/ベクタ領域を再設定可能にすることは珍しくありません... –

関連する問題