Linker Script und Externer RAM

#3618332
Lesenswert?

Hallo,

ich habe eine neue Entwicklungsumgebung für meinen STM32F4107ZG 
eingerichtet.
Die Entscheidung ist auf Em::Blocks (mit ARM GCC Compiler) gefallen.
Soweit läuft alles top ;).

An meinem STM32F4107ZG ist ein Externes RAM angeschlossen (ERAM1), 
woraus im LinkerSkript der folgende Memory Aufbau resultiert:

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

MEMORY
{
  IROM1   (RX)    : ORIGIN = 0x08000000,  LENGTH = 0x00100000
  IRAM2   (RW)    : ORIGIN = 0x10000000,  LENGTH = 0x00010000
  IRAM1   (XRW)   : ORIGIN = 0x20000000,  LENGTH = 0x00020000
  ERAM1   (RW)    : ORIGIN = 0x60000000,  LENGTH = 0x00080000
}

...

.bss :
{
   _sbss = .; /* define a global symbol at bss start */
   _bss_start_ = _sbss;
   *(.bss)
   *(.bss*)
   *(COMMON)

   . = ALIGN(4);
   _ebss = .; /* define a global symbol at bss end */
   _bss_end_ = _ebss;
} >IRAM1

...

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

Jetzt ist meine .bss-Sektion so groß das sie in keine der RAMs passt. 
Ich will dem LinkerSkript gerne folgendes sagen:
"Schreibe die .bss-Sektion erstmal in IRAM1 bis es voll ist, dann 
schreibe weiter in IRAM2 bis es voll ist und dann weiter in ERAM1."
Ich will sozusagen die RAMs aneinander hängen.

Ist das möglich?
Wenn ja, wie?

Viele Grüße
crozeg

.
Persönliche Seite #3618563
Lesenswert?

.bss2 :
{
   _sbss2 = .; /* define a global symbol at bss start */
   bss2_start = _sbss2;
   *(.bss2)
   *(.bss2*)
   *(COMMON)

   . = ALIGN(4);
   _ebss2 = .; /* define a global symbol at bss end */
   bss2_end = _ebss2;
} >ERAM1

und bei den Variablen Deklaration "__attribute__((section(".bss2")))"

das sollte dann passen. Vllt gibts auch n Makefile generator von 
Em:Blocks? Das man sowas über die Ide einstellen kann. Crossworks kann 
so was.
#3618564
Lesenswert?

Ch. Ziegler schrieb:
> Jetzt ist meine .bss-Sektion so groß das sie in keine der RAMs passt.
> Ich will dem LinkerSkript gerne folgendes sagen:
> "Schreibe die .bss-Sektion erstmal in IRAM1 bis es voll ist, dann
> schreibe weiter in IRAM2 bis es voll ist und dann weiter in ERAM1."

Ich hab's jetzt nicht selbst ausprobiert, das müsste aber eigentlich so 
gehen:
1
.bss1 :
2
{
3
   _sbss1 = .; /* define a global symbol at bss start */
4
   _bss_start_ = _sbss1;
5
   dir1/*(.bss)
6
   dir1/*(.bss*)
7
   dir1/*(COMMON)
8

9
   . = ALIGN(4);
10
   _ebss = .; /* define a global symbol at bss end */
11
   _bss_end_ = _ebss1;
12
} >IRAM1
13

14
.bss2 :
15
{
16
   _sbss2 = .; /* define a global symbol at bss start */
17
   _bss2_start_ = _sbss2;
18
   dir2/*(.bss)
19
   dir2/*(.bss*)
20
   dir2/*(COMMON)
21

22
   . = ALIGN(4);
23
   _ebss2 = .; /* define a global symbol at bss end */
24
   _bss2_end_ = _ebss2;
25
} > IRAM2
D.h. Du "sammelst" die Objektdateien in zwei Verzeichnissen, aus denen 
sich der Linker dann pro Segment bedient. So was wie einen 
"automatischen Überlauf" gibt's meiner Ansicht nach nicht.
#3619026
Lesenswert?

Ja, das nervt, dass die uC-Hersteller das RAM so zerstueckeln :(

Generell finde ich es aber sowieso schoener, die sections explizit im 
C-code anzugeben, damit man mit dem Linker-Script noch jonglieren kann. 
Wo man den Stack hinlegt wird ja wohl auch zu einer ganz wichtigen 
Entscheidung - vielleicht wichtiger als die die .bss Variablen.
Ich vermeide die .bss-Variablen meist zugunsten von Stack-Variablen, 
wegen deren Speicher-Wiederverwertung ;-)

Aber ich hoffe, dass noch ein Toolchain-Guru hier eine L"osung bietet.
Ich koennte sowas n"amlich sinngemaess in der .text brauchen...
#3619216
Lesenswert?

Tec Nologic schrieb:
> und bei den Variablen Deklaration "__attribute__((section(".bss2")))"

Gibt es anstatt "__attribute__((section(".bss2")))" auch ein #pragma für 
eine ganze C-Datei?


Markus F. schrieb:
> D.h. Du "sammelst" die Objektdateien in zwei Verzeichnissen, aus denen
> sich der Linker dann pro Segment bedient. So was wie einen
> "automatischen Überlauf" gibt's meiner Ansicht nach nicht.

Wie teilt man die *.o-Dateien auf verschiedene Unterverzeichnisse auf? 
Die Sourcedateien liegen bereits in verschiedenen Unterordnern, die 
O-Dateien werden beim Bauen in einem einzigen Ordner abgelegt.


Viele Grüße
crozeg
Persönliche Seite #3619237
Lesenswert?

Du kannst eine die bss section einer datei im Linkerskript angeben.
1
.bss2 :
2
{
3
   _sbss2 = .; /* define a global symbol at bss start */
4
   _bss2_start_ = _sbss2;
5
   dir2/*main.o(.bss .bss*) // hier wird bss von main gesetzt.
6
   dir2/*(.bss) //
7
   dir2/*(.bss*)
8
   dir2/*(COMMON)
9

10
   . = ALIGN(4);
11
   _ebss2 = .; /* define a global symbol at bss end */
12
   _bss2_end_ = _ebss2;
13
} > IRAM2

ich weis aber gerade nicht ob das ganz korrekt ist. Vllt weiß das noch 
jemand anderes.
Persönliche Seite #3619247
Lesenswert?

Korrektur:
1
There are two ways to include more than one section: 
2

3
*(.text .rdata)
4
*(.text) *(.rdata)
5

6
The difference between these is the order in which the `.text' and `.rdata' input sections will appear in the output section. In the first example, they will be intermingled. In the second example, all `.text' input sections will appear first, followed by all `.rdata' input sections. 
7

8
You can specify a file name to include sections from a particular file. You would do this if one or more of your files contain special data that needs to be at a particular location in memory. For example: 
9

10
data.o(.data)
1
.bss2 :
2
{
3
   _sbss2 = .; /* define a global symbol at bss start */
4
   _bss2_start_ = _sbss2;
5
   main.o(.bss) // hier wird bss von main gesetzt.
6
   foo.o(.bss)  // usw.
7
   dir2/*(.bss) //
8
   dir2/*(.bss*)
9
   dir2/*(COMMON)
10

11
   . = ALIGN(4);
12
   _ebss2 = .; /* define a global symbol at bss end */
13
   _bss2_end_ = _ebss2;
14
} > IRAM2
Persönliche Seite #3619253
Lesenswert?

also clean,
1
MEMORY
2
{
3
  IROM1   (RX)    : ORIGIN = 0x08000000,  LENGTH = 0x00100000
4
  IRAM2   (RW)    : ORIGIN = 0x10000000,  LENGTH = 0x00010000
5
  IRAM1   (XRW)   : ORIGIN = 0x20000000,  LENGTH = 0x00020000
6
  ERAM1   (RW)    : ORIGIN = 0x60000000,  LENGTH = 0x00080000
7
}
8

9
...
10

11
.bss :
12
{
13
   _sbss = .; /* define a global symbol at bss start */
14
   _bss_start_ = _sbss;
15
   main.o(.bss)
16
   *(.bss)
17
   *(.bss*)
18
   *(COMMON)
19

20
   . = ALIGN(4);
21
   _ebss = .; /* define a global symbol at bss end */
22
   _bss_end_ = _ebss;
23
} >IRAM1
24

25
.bss2 :
26
{
27
   _sbss2 = .; /* define a global symbol at bss start */
28
   _bss2_start_ = _sbss2;
29
   foo.o(.bss)
30
   *(.bss2)
31
   *(.bss2*)
32
   *(COMMON)
33

34
   . = ALIGN(4);
35
   _ebss2 = .; /* define a global symbol at bss end */
36
   _bss2_end_ = _ebss2;
37
} >ERAM1
#3619408
Lesenswert?

@tecnologic: das wird so nicht funktionieren.

Das würde bedeuten, daß der Linker selbstständig das nächste Segment 
nutzen würde, wenn er feststellt, daß eins "voll" ist (was er leider 
nicht tut). Es bleibt nichts anderes übrig, als den Überlauf "händisch" 
zu steuern.
#3619441
Lesenswert?

Schonmal vielen dank, ihr habt mir schon viel geholfen.

Momentan siehen meine bss-Sektionen wie folgt aus:
(Hoffe das stimmt soweit)
1
...
2

3
  .bss2 :
4
  {
5
    _sbss2 = .; /* define a global symbol at bss start */
6
    _bss2_start_ = _sbss2;
7

8
    obj/main.o(.bss .bss* COMMON)
9
    obj/hwe.o(.bss .bss* COMMON)
10

11
    /* FreeRTOS Objects */
12
    obj/port.o(.bss .bss* COMMON)
13
    obj/heap_4.o(.bss .bss* COMMON)
14
    obj/croutine.o(.bss .bss* COMMON)
15
    obj/event_groups.o(.bss .bss* COMMON)
16
    obj/list.o(.bss .bss* COMMON)
17
    obj/queue.o(.bss .bss* COMMON)
18
    obj/tasks.o(.bss .bss* COMMON)
19
    obj/timers.o(.bss .bss* COMMON)
20

21
    . = ALIGN(4);
22
    _ebss2 = .; /* define a global symbol at bss end */
23
    _bss2_end_ = _ebss2;
24
  } >IRAM1
25

26
  .bss :
27
  {
28
    _sbss = .; /* define a global symbol at bss start */
29
    _bss_start_ = _sbss;
30

31
    *(.bss)
32
    *(.bss*)
33
    *(COMMON)
34

35
    . = ALIGN(4);
36
    _ebss = .; /* define a global symbol at bss end */
37
    _bss_end_ = _ebss;
38
  } >ERAM1
39

40
...

Aber leider läuft meine Firmware nicht richtig.

Was genau scheinbar scheinen einige Dateien andere nicht mehr zu 
finden/erreichen?

Und was genau macht so ein AT befehl in LinkerScripts?
Zb im folgenden am ende meiner data-Sektion:
1
...
2
  .data :
3
  {
4
    . = ALIGN(4);
5
    _sdata = .;        /* create a global symbol at data start */
6
    *(.data)           /* .data sections */
7
    *(.data*)          /* .data* sections */
8

9
    . = ALIGN(4);
10
    _edata = .;        /* define a global symbol at data end */
11
  } >ERAM1 AT> IROM1
12
...

Viele Grüße
crozeg
#3619471
Lesenswert?

Ch. Ziegler schrieb:

> Und was genau macht so ein AT befehl in LinkerScripts?
> Zb im folgenden am ende meiner data-Sektion:
>
1
> ...
2
>   .data :
3
>   {
4
>     . = ALIGN(4);
5
>     _sdata = .;        /* create a global symbol at data start */
6
>     *(.data)           /* .data sections */
7
>     *(.data*)          /* .data* sections */
8
> 
9
>     . = ALIGN(4);
10
>     _edata = .;        /* define a global symbol at data end */
11
>   } >ERAM1 AT> IROM1
12
> ...
>
> Viele Grüße
> crozeg

das AT-Konstrukt packt die Objektdaten an die erste Adresse (ERAM1), 
reloziert den Code aber so, daß sie ab der zweiten Adresse (IROM1) 
referenziert werden.
Für dich bedeutet das, daß dein ausführbarer Code seine Daten ab der 
Startadresse IROM1 erwartet (wo sie aber nicht sind, falls Du sie nicht 
beim Programmstart umkopierst).

Das kann so m.E. nicht gut gehen.
#3619871
Lesenswert?

Hallo,

danke schonmal, seit dem nullen im startup code läufts schon besser. 
Zumindest die main.o.
1
...
2
  . = ALIGN(4);
3
  .bss_iram1 :
4
  {
5
    _sbss_iram1 = .; /* define a global symbol at bss start */
6
    _bss_iram1_start_ = _sbss_iram1;
7

8
    obj/main.o(.bss .bss* COMMON)
9
    obj/rm_tcp.o(.bss .bss* COMMON)
10

11
    /* FreeRTOS Objects */
12
    obj/port.o(.bss .bss* COMMON)
13
    obj/heap_4.o(.bss .bss* COMMON)
14
    obj/croutine.o(.bss .bss* COMMON)
15
    obj/event_groups.o(.bss .bss* COMMON)
16
    obj/list.o(.bss .bss* COMMON)
17
    obj/queue.o(.bss .bss* COMMON)
18
    obj/tasks.o(.bss .bss* COMMON)
19
    obj/timers.o(.bss .bss* COMMON)
20

21
    . = ALIGN(4);
22
    _ebss_iram1 = .; /* define a global symbol at bss end */
23
    _bss_iram1_end_ = _ebss_iram1;
24
  } >IRAM1
25

26

27
  . = ALIGN(4);
28
  .bss_eram1 :
29
  {
30
    /* This is used by the startup in order to initialize the .bss secion */
31
    _sbss_eram1 = .;         /* define a global symbol at bss start */
32
    __bss_eram1_start__ = _sbss_eram1;
33

34
    *(.bss)
35
    *(.bss*)
36
    *(COMMON)
37

38
    . = ALIGN(4);
39
    _ebss_eram1 = .;         /* define a global symbol at bss end */
40
    __bss_eram1_end__ = _ebss_eram1;
41
  } >ERAM1
42
...

Wenn ich die Zeile "obj/rm_tcp.o(.bss .bss* COMMON)" zur bss_iram1 
hinzufüge funktioniert nichts mehr. Der Compiler wirft folgendes:
1
Linking executable: bin\Debug\FreeRTOS4EGM.elf
2
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `_cleanup_r':
3
findfp.c:(.text._cleanup_r+0x0): multiple definition of `_cleanup_r'
4
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text._cleanup_r+0x0): first defined here
5
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfmoreglue':
6
findfp.c:(.text.__sfmoreglue+0x0): multiple definition of `__sfmoreglue'
7
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfmoreglue+0x0): first defined here
8
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `_cleanup':
9
findfp.c:(.text._cleanup+0x0): multiple definition of `_cleanup'
10
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text._cleanup+0x0): first defined here
11
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sinit':
12
findfp.c:(.text.__sinit+0x0): multiple definition of `__sinit'
13
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sinit+0x0): first defined here
14
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfp':
15
findfp.c:(.text.__sfp+0x0): multiple definition of `__sfp'
16
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfp+0x0): first defined here
17
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfp_lock_acquire':
18
findfp.c:(.text.__sfp_lock_acquire+0x0): multiple definition of `__sfp_lock_acquire'
19
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfp_lock_acquire+0x0): first defined here
20
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sfp_lock_release':
21
findfp.c:(.text.__sfp_lock_release+0x0): multiple definition of `__sfp_lock_release'
22
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sfp_lock_release+0x0): first defined here
23
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sinit_lock_acquire':
24
findfp.c:(.text.__sinit_lock_acquire+0x0): multiple definition of `__sinit_lock_acquire'
25
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sinit_lock_acquire+0x0): first defined here
26
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__sinit_lock_release':
27
findfp.c:(.text.__sinit_lock_release+0x0): multiple definition of `__sinit_lock_release'
28
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__sinit_lock_release+0x0): first defined here
29
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__fp_lock_all':
30
findfp.c:(.text.__fp_lock_all+0x0): multiple definition of `__fp_lock_all'
31
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__fp_lock_all+0x0): first defined here
32
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc_n.a(lib_a-findfp.o): In function `__fp_unlock_all':
33
findfp.c:(.text.__fp_unlock_all+0x0): multiple definition of `__fp_unlock_all'
34
c:/program files (x86)/emblocks/1.45/share/em_armgcc/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7e-m/fpu\libc.a(lib_a-findfp.o):findfp.c:(.text.__fp_unlock_all+0x0): first defined here
35
collect2.exe: error: ld returned 1 exit status
36
Process terminated with status 1 (0 minutes, 5 seconds)
37
0 errors, 165 warnings (0 minutes, 5 seconds)

Siehe auch angehängtes Bild.

Im Bild sieht man auch das der Build mit 0 Errors abgeschlossen wurde, 
aber ich kann den Code nicht Debuggen/ins Target laden.


Viele Grüße
crozeg
Angehängte Dateien:

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