Cortex M4/STM32F4: Problem mit BLX Instruktion

Gast #3379681
Lesenswert?

Hallo zusammen,

ich hoffe hier jemanden zu finden, der mit meiner Frage etwas anzufangen 
vermag, wenn sie vielleicht auch "laienhaft" gestellt sein mag ;-)

Mein eigentliches Problem ist hier beschrieben:
Beitrag "CooCox problem mit memset"

Mittlerweile glaube ich aber nicht mehr, dass das Problem mit der 
Einrichtung eines Heaps zu tun hat, da freeRTOS eine eigene 
Speicherverwaltung implementiert die an malloc vorbei geht.

Im beigefügten Bild sieht man, dass der Program Counter vor dem Aufruf 
von memset steht. Im Disassembly Window führt die Anweisung

blx 0x8002e2c <memset> (**)

dann zu einer Exception.

Die erste Frage

Im Cortex M4 Manual "PM0214 Programming manual" finde ich die BLX 
Instruktion folgendermaßen beschrieben:

B{cond} label
BL{cond} label
BX{cond} Rm
BLX{cond} Rm
.
.
BLX Is branch indirect with link (register).
.
.
Also sollte ein BLX <label> (**) doch gar nicht existieren. Wieso setzt 
mein Compiler diesen Befehl ab?

Die zweite Frage

Anderswo steht:
"if you generate a target address for a BX or BLX instruction, you must 
ensure that bit[0]
of the address you generate is set to 1 for correct execution."

Bei mir ist die Target Adresse 0x8002e2c, also ist bit-0 nicht gesetzt. 
Deshalb vermute ich mal ungeniert, dass das auch die Ursache für die 
Exception ist, die ich erhalte, wenn das BLX ausgeführt wird. Trifft 
diese Vermutung zu?

-> Falls ja, wie kann ich erreichen, dass der Compiler kein BLX absetzt, 
bzw. was mache ich falsch und warum passiert das überhaupt?

Kann es sein, dass ich eine "falsche" c-Library verwende?

-> Falls ja, wo finde ich die richtige unter der arm-none-eabi-gcc-4_6 
toolchain?


Ich wäre für eine Expertenantwort oder einen Tip sehr dankbar, da ich 
schon zwei Tage an dieser Stelle hänge und nicht mehr weiß, was ich tun 
soll ;-)

Liebe Grüße,
Michael
Angehängte Dateien:
Gast #3379698
Lesenswert?

Dennis Heynlein schrieb:
> Denkst du daran, daß unterste Bit zu setzen in der Adresse ?
> Der Cortex-Mx kann nur Thumb2 und das muß durch ein gesetztes Bit 0
> signalisiert werden, sonst knallts.

Danke für die Antwort.
Mir ist klar dass es wohl aus diesem Grund knallt. Das Ergebnis ist aber 
ein Code, den der c-Compiler abgesetzt hat. Wie kann ich das verhindern?
Gast #3379702
Lesenswert?

Dennis Heynlein schrieb:
> Dein Memset-Problem ist wo anders, erhöhe mal die Granularität des Heaps
> von FreeRTOS auf minimum 4.

und wo?

Ich finde nur im freeRTOSConfig.h:

#define configTOTAL_HEAP_SIZE  ( ( size_t ) ( 40960 ) )

und das wird es ja wohl nicht sein, oder?

Übrigens: Was hat das mit dem nicht gesetzten Bit[0] zu tun?
Gast #3379706
Lesenswert?

ARM DDI 0403D (ARM ARMv7-M):

Branch with Link and Exchange calls a subroutine at an address and 
instruction set specified by a register.
ARMv7-M only supports the Thumb instruction set. An attempt to change 
the instruction execution state
causes the processor to take an exception on the instruction at the 
target address.

ARM DDI 0406C.b (ARM ARMv7AR):
--------------
The BLX (immediate) instruction switches between ARM and Thumb states 
and branches to the value written
to the PC. Its definition ensures that the value written to the PC is 
correctly aligned for the new instruction
set state.

--------------

Hast Du den richtigen Core eingestellt?
Gast #3379709
Lesenswert?

Dennis Heynlein schrieb:
> welchen Heap nimmst du ?

Das ist das Problem aus dem ersten Posting: Ich habe keinen speziellen 
Heap eingerichtet und weiß auch nicht, wie ich das tun soll, da ich 
(noch) keine Linker Scripts schreiben kann.

Das ist jedenfalls das Default Script:
1
       [cc] opened script file P:\CooCox\CoIDE\configuration\ProgramData\rtostest/arm-gcc-link.ld
2
       [cc] using external linker script:
3
       [cc] ==================================================
4
       [cc] OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
5
       [cc] /* Internal Memory Map*/
6
       [cc] MEMORY
7
       [cc]   rom (rx)  : ORIGIN = 0x08000000, LENGTH = 0x00100000
8
       [cc] {
9
       [cc]   ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
10
       [cc]   ram1 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000
11
       [cc] }
12
       [cc] 
13
       [cc] _eram = 0x20000000 + 0x00020000;
14
       [cc] /* Section Definitions */ 
15
       [cc] SECTIONS 
16
       [cc] { 
17
       [cc]     .text : 
18
       [cc]     { 
19
       [cc]         KEEP(*(.isr_vector .isr_vector.*)) 
20
       [cc]         *(.text .text.* .gnu.linkonce.t.*)         
21
       [cc]         *(.glue_7t) *(.glue_7)                    
22
       [cc]         *(.rodata .rodata* .gnu.linkonce.r.*)                            
23
       [cc]     } > rom
24
       [cc]     
25
       [cc]     .ARM.extab : 
26
       [cc]     {
27
       [cc]         *(.ARM.extab* .gnu.linkonce.armextab.*)
28
       [cc]     } > rom
29
       [cc]     
30
       [cc]     __exidx_start = .;
31
       [cc]     .ARM.exidx :
32
       [cc]     {
33
       [cc]         *(.ARM.exidx* .gnu.linkonce.armexidx.*)
34
       [cc]     } > rom
35
       [cc]     __exidx_end = .;
36
       [cc]     
37
       [cc]     . = ALIGN(4); 
38
       [cc]     _etext = .;
39
       [cc]     _sidata = .; 
40
       [cc]         
41
       [cc]     .data : AT (_etext) 
42
       [cc]     { 
43
       [cc]         _sdata = .; 
44
       [cc]         *(.data .data.*) 
45
       [cc]         . = ALIGN(4); 
46
       [cc]         _edata = . ;
47
       [cc]     } > ram
48
       [cc] 
49
       [cc]     /* .bss section which is used for uninitialized data */ 
50
       [cc]     .bss (NOLOAD) : 
51
       [cc]     { 
52
       [cc]         _sbss = . ; 
53
       [cc]         *(.bss .bss.*) 
54
       [cc]         *(COMMON) 
55
       [cc]         . = ALIGN(4); 
56
       [cc]         _ebss = . ; 
57
       [cc]     } > ram
58
       [cc]     
59
       [cc]     /* stack section */
60
       [cc]     .co_stack (NOLOAD):
61
       [cc]     {
62
       [cc]         . = ALIGN(8);
63
       [cc]         *(.co_stack .co_stack.*)
64
       [cc]     } > ram
65
       [cc]        
66
       [cc]     . = ALIGN(4); 
67
       [cc]     _end = . ; 
68
       [cc] }

Ich habe bisher noch nie einen expliziten Heap gebraucht. Wann braucht 
man einen solchen und was hat das mit dem nicht gesetzten Bit[0] zu tun 
?

Danke, Michael
Persönliche Seite #3379727
Lesenswert?

gopher schrieb:
> Dennis Heynlein schrieb:
>> B / BL sind die direkt-adress-codierten Varianten.
>> BX / BLX sind die Varianten mit dem Register als Sprungziel.
>
> Bitte nochmal bei ARM nachlesen!
>
> X = Wechsel zwischen ARM und Thumb Mode!

Gern.

-> 
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABEFHAE.html

Da gibts ein Paar Besonderheiten die dir vielleicht entgangen sind bei 
ARMV7-M
Gast #3379737
Lesenswert?

gopher schrieb:
> Hallo Michael,
>
> welche -march oder -mcpu Option wird in Deinem Fall verwendet (siehe
> Console Output)?

Hier mein Compileraufruf aus der Console:

arm-none-eabi-gcc -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard 
-mthumb -Wall -ffunction-sections -g -O0 -DHSE_VALUE=8000000 -c 
-DSTM32F407VG -DSTM32F4XX -DUSE_STDPERIPH_DRIVER -D__ASSEMBLY__ 
-D__FPU_USED -ID:\controller\CoIDE_Workspace\workspace -
...
...

       [cc] Starting link
       [cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -g -nostartfiles 
-Wl,-Map=rtostest.map -O0 -Wl,--gc-sections -Wl,--verbose 
-LP:\CooCox\CoIDE\configuration\ProgramData\rtostest 
-Wl,-TP:\CooCox\CoIDE\configuration\ProgramData\rtostest/arm-gcc-link.ld 
-g -o rtostest.elf '"C:\Program 
Files\arm-none-eabi-gcc-4_6\arm-none-eabi\lib\fpu\libc.a"' 
..\obj\startup_stm32f4xx.o ..\obj\main.o ..\obj\stm32f4xx_rcc.o 
..\obj\timers.o ..\obj\tasks.o ..\obj\stm32f4xx_gpio.o ..\obj\list.o 
..\obj\system_stm32f4xx.o ..\obj\port.o ..\obj\queue.o ..\obj\croutine.o 
..\obj\heap_1.o ..\obj\configuration.o "-LC:\Program 
Files\arm-none-eabi-gcc-4_6\arm-none-eabi\lib\fpu" -lm -lgcc -lc
       [cc] GNU ld (GNU Tools for ARM Embedded Processors) 
2.21.1.20110908
       [cc]   Supported emulations:
Gast #3379748
Lesenswert?

Jim Meba schrieb:
> Der OP hat vergessen den MCU Typ dem Linker mitzuteilen - der nimmt per
> default den ARM statt Thumb Befehlssatz. Deshalb wird eine BLX
> Instruktion generiert, denn das Ziel ist ARM Code.
>
> Abhilfe ist die korrekte Angabe der Zielplatform auch für den Linker.

Hier ist doch der Linker mit -mcpu=cortex-m4 versorgt, oder?
1
       [cc] Starting link
2
       [cc] arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -g -nostartfiles 
3
-Wl,-Map=rtostest.map -O0 -Wl,--gc-sections -Wl,--verbose 
4
-LP:\CooCox\CoIDE\configuration\ProgramData\rtostest 
5
-Wl,-TP:\CooCox\CoIDE\configuration\ProgramData\rtostest/arm-gcc-link.ld 
6
-g -o rtostest.elf '"C:\Program 
7
Files\arm-none-eabi-gcc-4_6\arm-none-eabi\lib\fpu\libc.a"' 
8
..\obj\startup_stm32f4xx.o ..\obj\main.o ..\obj\stm32f4xx_rcc.o 
9
..\obj\timers.o ..\obj\tasks.o ..\obj\stm32f4xx_gpio.o ..
Gast #3379749
Lesenswert?

Jim Meba schrieb:
> Der OP hat vergessen den MCU Typ dem Linker mitzuteilen - der nimmt per
> default den ARM statt Thumb Befehlssatz. Deshalb wird eine BLX
> Instruktion generiert, denn das Ziel ist ARM Code.
>
> Abhilfe ist die korrekte Angabe der Zielplatform auch für den Linker.

Ausweislich seines Console Logs hat er das auch gemacht.

Michael: Bist Du Dir sicher, dass Du das richtige Image debuggst?
Gast #3379753
Lesenswert?

gopher schrieb:
> Ändert trotzdem nix dran, dass "X" = exchange.

Ist es für dich nun klar, warum mein Fehler passiert?
Warum erzeugt der Compiler einen Change auf ARM ?

Kann es sein, dass die von mir verwendete lic.a für "ARM" statt "thumb" 
generiert wurde, und der Compiler DESHALB den switch macht?
Gast #3379758
Lesenswert?

Michael W. schrieb:
> gopher schrieb:
>> Ändert trotzdem nix dran, dass "X" = exchange.
>
> Ist es für dich nun klar, warum mein Fehler passiert?
> Warum erzeugt der Compiler einen Change auf ARM ?
>


Nein, ist mir nicht. MMn machst Du alles richtig.
Lass' doch mal ein Listfile mit AssemblerOutput
erzeugen.

> Kann es sein, dass die von mir verwendete lic.a für "ARM" statt "thumb"
> generiert wurde, und der Compiler DESHALB den switch macht?

Was ist lic.a? Oder sollte das libc.a heissen?

Nein, die Auswahl der richtigen Lib durch den Linker muss anhand der 
-march oder -mcpu Option erfolgen.
Persönliche Seite #3379774
Lesenswert?

gopher.
Wir können uns ja jetzt drüber Streiten. Aber der ARMv7-M versteht BLX 
und er macht auch genau das was er soll.
Am untersten Bit der Sprungadresse bestimmt der ARM7 welcher 
Instructionset an der Sprungadresse gilt.
Ein Bit[0]=ARM32, ein Bit[0]=Thumb(2).
Probiere es bitte selbst aus, ein Üblicher Cortex-M3/M4 reicht.

Und Michael, irgendwo hast du dem Compiler noch nicht klipp und klar 
erklärt das es sich um einen Only-Thumb2 dreht.
Ein ARMv7-M muß ausgewählt werden, kein ARMv7-A oder -R.
Gast #3379784
Lesenswert?

gopher schrieb:
> Ändert trotzdem nix dran, dass "X" = exchange.

Ist es für dich nun klar, warum mein Fehler passiert?
Warum erzeugt der Compiler einen Change auf ARM ?

Kann es sein, dass die von mir verwendete lic.a für "ARM" statt "thumb" 
generiert wurde, und der Compiler DESHALB den switch macht?

gopher schrieb:
> Was ist lic.a? Oder sollte das libc.a heissen?
>
> Nein, die Auswahl der richtigen Lib durch den Linker muss anhand der
> -march oder -mcpu Option erfolgen.

Ich habe unter CooCox eine Link Maske (siehe Anhang).

Nehme ich die c-Library libc.a aus dem fpu Ordner des gcc lib 
Vrzeichnisses, so habe ich mein aktuelles Problem.

Es gibt auch ein Verzeichnis "thumb", wo ebenfalls ein libc.a drin ist. 
Das führt aber wieder zu einen Fehler (siehe Bild). Da gibt es aber 
dutzende libc.a, libg.a, libnosys.a, etc... in verschiedensten 
Verzeichnissen, sodass ich nicht weiß, welche die richtige ist...
Angehängte Dateien:
Gast #3379802
Lesenswert?

Dennis Heynlein schrieb:
> Und Michael, irgendwo hast du dem Compiler noch nicht klipp und klar
> erklärt das es sich um einen Only-Thumb2 dreht.
> Ein ARMv7-M muß ausgewählt werden, kein ARMv7-A oder -R.

Ok, das hat geholfen. Ich habe jetzt im Ordner armv7e-m/thumb eine 
Version von libc.a gefunden, die kein BLX, sondern ein BL erzeugt. Nun 
komme ich über den memset Befehl unbeschadet hinweg.

Was ist nun armv7e-m ? Ich habe nirgends eine Beschreibung gefunden und 
nur nach Bauchgefühl gehandelt.

Wieso gibt es so viele verschiedene libc.a ? Mein vorheriges libc.a war 
offenbar für einen ARM7 gedacht - sehe ich dies richtig?

Danke einmal!!!!
Persönliche Seite #3379805
Lesenswert?

|Cortex-M4 | -mthumb -mcpu=cortex-m4                    | armv7e-m |
|(No FP)   |--------------------------------------------|          |
|          | -mthumb -march=armv7e-m                    |          |
|----------|--------------------------------------------|----------|
|Cortex-M4 | -mthumb -mcpu=cortex-m4 -mfloat-abi=softfp | armv7e-m |
|(Soft FP) | -mfpu=fpv4-sp-d16                          | /softfp  |
|          |--------------------------------------------|          |
|          | -mthumb -march=armv7e-m -mfloat-abi=softfp |          |
|          | -mfpu=fpv4-sp-d16                          |          |
|----------|--------------------------------------------|----------|
|Cortex-M4 | -mthumb -mcpu=cortex-m4 -mfloat-abi=hard   | armv7e-m |
|(Hard FP) | -mfpu=fpv4-sp-d16                          | /fpu     |
|          |--------------------------------------------|          |
|          | -mthumb -march=armv7e-m -mfloat-abi=hard   |          |
|          | -mfpu=fpv4-sp-d16                          |


https://launchpadlibrarian.net/151487295/readme.txt
Gast #3379817
Lesenswert?

Dennis Heynlein schrieb:
> |Cortex-M4 | -mthumb -mcpu=cortex-m4                    | armv7e-m |
> |(No FP)   |--------------------------------------------|          |
> |          | -mthumb -march=armv7e-m                    |          |
> |----------|--------------------------------------------|----------|
> |Cortex-M4 | -mthumb -mcpu=cortex-m4 -mfloat-abi=softfp | armv7e-m |
> |(Soft FP) | -mfpu=fpv4-sp-d16                          | /softfp  |
> |          |--------------------------------------------|          |
> |          | -mthumb -march=armv7e-m -mfloat-abi=softfp |          |
> |          | -mfpu=fpv4-sp-d16                          |          |
> |----------|--------------------------------------------|----------|
> |Cortex-M4 | -mthumb -mcpu=cortex-m4 -mfloat-abi=hard   | armv7e-m |
> |(Hard FP) | -mfpu=fpv4-sp-d16                          | /fpu     |
> |          |--------------------------------------------|          |
> |          | -mthumb -march=armv7e-m -mfloat-abi=hard   |          |
> |          | -mfpu=fpv4-sp-d16                          |
>
>
> https://launchpadlibrarian.net/151487295/readme.txt

OK, das macht Sinn...
Im Nachhinein klar ;-) Wieder mal zwei Tage unnötig vergeudet...
Diese Tabelle kannte ich nicht.


Ich hoffe, dass das RTOS nun auch funktioniert und werde morgen gleich 
testen. Was hat es mit der Aktivierung des Heaps auf sich? Ich habe 
keinen expliziten Heap eingereichtet, da ich angenommen habe, dass ich 
das bei Heap2.c nicht brauche (malloc wird nicht verwendet). Oder etwa 
doch?

Danke !!!
Gast #3379844
Lesenswert?

Michael W. schrieb:
> gopher schrieb:
>> Ändert trotzdem nix dran, dass "X" = exchange.
>

> Es gibt auch ein Verzeichnis "thumb", wo ebenfalls ein libc.a drin ist.
> Das führt aber wieder zu einen Fehler (siehe Bild). Da gibt es aber

Die Meldung "uses VFP..." ist auch ein Indiz, dass Cortex-Ax wirksam 
ist,
Cortex-M4 hat zwar eine FPU, aber keinen VFP (Vector Floating Point)


> dutzende libc.a, libg.a, libnosys.a, etc... in verschiedensten
> Verzeichnissen, sodass ich nicht weiß, welche die richtige ist...
....

>Ein ARMv7-M muß ausgewählt werden, kein ARMv7-A oder -R.

Das sollte aber eine zwangsläufige Folge von -mcpu=cortex-m4 sein...

Noch ein Tip:
Es gibt Tools wie (arm-none-eabi...)-objdump, -readelf, -nm etc. (die 
auch bei einer Windows-Installation von GCC verfügbar sein sollten), die
über den Inhalt eines Objects oder eine Lib Auskunft geben...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren