Forum: Mikrocontroller und Digitale Elektronik GCC Linker per Linker Script oder über Kommandozeile Parameter zum Setzen einer Konstante mitgeben


von Daniel -. (root)


Lesenswert?

Hallo,

besteht eine Möglichkeit dem Linker einen uint32 Wert mitzugeben und
damit eine Konstante zu initialisieren.
1
const uint32_t app_checksum __attribute__((section(".appdata"), used)) = 0xAABBCCDD;
2
const uint32_t app_numpages __attribute__((section(".appdata"), used)) = 100;   // num of 2kB pages
1
  /* Constant data into "FLASH" Rom type memory */
2
  .rodata :
3
  {
4
    . = ALIGN(4);
5
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
6
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
7
    KEEP(*(.appdata))   /* checksum and length of the app */
8
    . = ALIGN(4);
9
  } >FLASH
1
$ arm-none-eabi-objdump.exe -s -j .rodata const_var.elf
2
const_var.elf:     file format elf32-littlearm
3
Contents of section .rodata:
4
 8002bc0 00000000 00000000 01020304 06070809  ................
5
 8002bd0 02030405 06070809 0a0b0c0d 0e0f1010  ................
6
 8002be0 01020304 05060708 090a0b0c 0d0e0f10  ................
7
 8002bf0 ddccbbaa 64000000                    ....d...
8
 ^addr   ^value

Erste Idee war mit einem Binary Editor den Wert auszutauschen
und dann HEX daraus zu machen. Diese Vorgehensweise lässt sich nicht
robust per Makefile umsetzen, da die Variablenaddressen sich ändern.

Zweite Idee war die GCC Toolchain dafür einzusetzen.
Hat jemand ein Beispiel wie man mit objcopy einen Wert in einer
Sektion austauschen kann? Am besten mit Referenz auf Symbol und
nicht eine Adresse.
Hat jemand vielleicht ein Beispiel wie man mit ld das machen kann?
Kann man da nicht mit
1
_vorher = .;
2
KEEP(*(.appdata))   /* checksum and length of the app */
3
_nacher = .;
die Adresse herausfinden und diese zum Setzen neuer Werte benutzen?

ChatGPT hat mir elftools aufschwatzen wollen. Die elf Datei ist danach
vom 2Meg auf 200Meg gegangen. Warum ist mir noch nicht klar.
Wird da beim Schreiben auf eine Adresse der ganze Adressraum ausgerollt?

Bisher habe ich zum Ablegen der Checksumme srec_cat benutzt.
srec_cat in.hex -intel -crop 0x08000000 0x0803EFFC -STM32 0x0803EFFC -o 
out.hex -intel
Allerdings wird hier ganze Page für 32bit Checksumme verbraucht.
Und damit die Checksumme passt, sind -fill 0xFF und -unfill 0xFF Aufrufe 
notwendig.

Viele Grüße

von Kaj G. (Firma: RUB) (bloody)


Lesenswert?

Du suchst die Option -D
https://www.rapidtables.com/code/linux/gcc/gcc-d.html

https://www.man7.org/linux/man-pages/man1/gcc.1.html
1
       -D name
2
           Predefine name as a macro, with definition 1.
3
4
       -D name=definition
5
           The contents of definition are tokenized and processed as if
6
           they appeared during translation phase three in a #define
7
           directive.  In particular, the definition is truncated by
8
           embedded newline characters.
9
10
           If you are invoking the preprocessor from a shell or shell-
11
           like program you may need to use the shell's quoting syntax
12
           to protect characters such as spaces that have a meaning in
13
           the shell syntax.
14
15
           If you wish to define a function-like macro on the command
16
           line, write its argument list with surrounding parentheses
17
           before the equals sign (if any).  Parentheses are meaningful
18
           to most shells, so you should quote the option.  With sh and
19
           csh, -D'name(args...)=definition' works.
20
21
           -D and -U options are processed in the order they are given
22
           on the command line.  All -imacros file and -include file
23
           options are processed after all -D and -U options.

von Oliver S. (oliverso)


Lesenswert?

Es ist etwas unklar, was du genau machn möchtest.

Wenn du die Konstanten im Sourcefile setzen möchtest, dann ist die schon 
genannte Compileroption -D dafür geeignet.

Wenn du Linkersymbole setzen willst, hat der linker dafür die Option 
--defsym.

https://sourceware.org/binutils/docs/ld/Options.html

Oliver

: Bearbeitet durch User
von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Ich nutze so etwas, um eine Konfiguration in einem  bestimmten 
Speicherbereich eines nrf52 fest zu legen:
1
SECTIONS {
2
    .bootloader_addr 0x10001014 :
3
    {
4
        workaround_for_ld_removing_the_next_symbols = .;
5
        LONG(458752)
6
        LONG(454656)
7
    } > UICR
8
}

von Bauform B. (bauformb)


Lesenswert?

Daniel -. schrieb:
> Erste Idee war mit einem Binary Editor den Wert auszutauschen
> und dann HEX daraus zu machen. Diese Vorgehensweise lässt sich nicht
> robust per Makefile umsetzen, da die Variablenaddressen sich ändern.

Müssen sie sich ändern? Kann man sie nicht in eine eigene section 
packen, z.B. direkt hinter der vectortable? Weil, die erste Idee ist 
manchmal die beste.

Kaj G. schrieb:
> -D name
>            Predefine name as a macro, with definition 1.

Das geht doch nur auf dem "Umweg" über Präprozessor und Compiler? 
Eigentlich kein Problem, aber manchmal muss es der Linker alleine 
machen. Ich hatte sowas mal für einen Zeitstempel benutzt, aber es sieht 
hässlich aus:
1
# Makefile
2
UTC := $(shell date +%s)
3
CFLAGS = -Wall -Wl,-defsym=BUILD_TIME=$(UTC)
1
extern int  BUILD_TIME;
2
time_t build_time = (time_t)&BUILD_TIME;

von Martin H. (horo)


Lesenswert?

Daniel -. schrieb:
> Hat jemand ein Beispiel wie man mit objcopy einen Wert in einer
> Sektion austauschen kann? Am besten mit Referenz auf Symbol und
> nicht eine Adresse.

Ich hatte mal vor vielen Jahren sowas für den Micronucleus 
zusammengehackt und dazu "objcopy" verwendet.

https://github.com/micronucleus/micronucleus/commit/b9b7e85ce887c3ff4f0b38273dcd32e9d9810f8f

Nachdem es funktionierte habe ich nicht mehr daran gedreht. Es ging 
darum, den neuen Bootloader (raw binary) zusammen mit den Routinen zum 
Nachflashen zu linken. Die passenden Zeilen finden sich im aktuellen 
Makefile vom Firmware-Repo, vielleicht kannst Du es ja als Anregung 
nehmen.

https://github.com/ArminJo/micronucleus-firmware/blob/18ad3420ccdfb3f21638cd06be99a5e6574ccb0d/firmware/Makefile#L151-L158
1
bootloader.o: bootloader.raw
2
        @avr-objcopy -I binary -O elf32-avr \
3
        --rename-section .data=.text \
4
        --redefine-sym _binary_$*_raw_start=$* \
5
        --redefine-sym _binary_$*_raw_end=$*_end \
6
        --redefine-sym _binary_$*_raw_size=$*_size_sym \
7
        $(AVR_ARCHITECTURE_PARAMETER) \
8
        $< $@

von Daniel -. (root)


Lesenswert?

Bauform B. schrieb:
> Müssen sie sich ändern? Kann man sie nicht in eine eigene section
> packen, z.B. direkt hinter der vectortable? Weil, die erste Idee ist
> manchmal die beste.

ich werde es wohl so machen müssen. Auch im Linker Skript eigene
Output Sektion machen, weil die Checksumme auch über rodata gehen soll
und diese wird nach Platzierung der Checksumme die Checksummenberechnung
ändern. War Gedankenfehler meinerseits.

Danke für das Beispiel mit Buildtime und LONG(454656).
Damit sollte es über Makefile automatisierbar sein.

Gruß

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.