Forum: Mikrocontroller und Digitale Elektronik LPC11C24: Problem mit rand / __aeabi_lmul


von Ralph S. (jjflash)


Angehängte Dateien:

Lesenswert?

Ich bin am Aufsetzen (für meine "Gesamtsystem") eines Setups für einen 
LPC11Cx4 Controller.

Hier habe ich u.a. die Zuweisungen der Registernamen und Registerbits zu 
ihren Adressen (mühselig) zusammengepfriemelt und es funktioniert bis 
hierher auch recht ordentlich.

Allerdings habe ich sprichwörtlich jetzt einen Fehler im System:

Die Funktion

rand()

aus libc will nicht so richtig!

Diese ruft wohl __aeabi_lmul auf und diese Funktion wird nicht gefunden 
(leider).

Mir eigentlich schleierhaft, weil ich dieselbe libc (genauso wie libgcc 
und libm) für STM32F0 verwendet (allerdings mit libopencm3) und dort 
funktioniert alles.

Die Fehlermeldung des Compiler / Linkers ist:
1
arm-none-eabi-ld rand_test.o ../src/smallio.o ../lib/startup.o -L ../lib -flto -lm -lgcc -lc -lnosys -T lpc11cx4.ld -nostartfiles -o rand_test.elf
2
../lib/libc.a(lib_a-rand.o): In function `rand':
3
rand.c:(.text.rand+0x10): undefined reference to `__aeabi_lmul'
4
../lib/makefile.mk:49: recipe for target 'all' failed
5
make: *** [all] Error 1


Die Datei makefile.mk wird von Makefile inkludiert (damit ich den 
funktionalen Teil nicht immer neu schreiben muss).

Im makefile.mk habe ich (natürlich... und wider besseren Wissens) 
folgendes versucht:
1
LDFLAGS      = -flto -lm --start-group -lgcc -lc -lnosys

anstelle von
1
LDFLAGS      = -flto -lm -lgcc -lc -lnosys

Dadurch ist zwar der Fehler des Linkers weg, aber natürlich findet er 
die Funktion dennoch nicht und rand() liefert immer denselben Wert.

Natürlich habe ich auch die libc_nano des arm-none-eabi-gcc ausprobiert, 
mit demselben Ergebnis, als ob ich --start-group mit angebe: Der Fehler 
im Compiler ist weg, rand() funktioniert denoch nicht !

Was kann ich tun ?

von Programmierer (Gast)


Lesenswert?

Ralph S. schrieb:
> Dadurch ist zwar der Fehler des Linkers weg, aber natürlich findet er
> die Funktion dennoch nicht und rand() liefert immer denselben Wert.

srand() aufgerufen...? Was heißt "findet die Funktion dennoch nicht"? 
Sagt dir der Mikrocontroller "Ich finde die Funktion nicht"? Warum 
linkst du mit "ld" und nicht mit "gcc"?

von Ralph S. (jjflash)


Lesenswert?

Programmierer schrieb:
> srand() aufgerufen...?

Hab ich mit und ohne vorherigen Aufruf gemacht, gleiches Ergebnis.

Programmierer schrieb:
> linkst du mit "ld" und nicht mit "gcc"?

Weil ld das Linkerprogramm ist ?!?

Ich hab mit beiden gelinkt, mit gcc und mit ld... das gleiche!

Programmierer schrieb:
> Sagt dir der Mikrocontroller "Ich finde die Funktion nicht"?

Auf seine Art und Weise tut er das, weil er wohl irgendwas aus dem 
Speicher nimmt, nur nicht das was er soll.

Ich nehme mir mal den Assembleroutput vor

von Programmierer (Gast)


Lesenswert?

Ralph S. schrieb:
> Hab ich mit und ohne vorherigen Aufruf gemacht, gleiches Ergebnis.

Und auch hoffentlich jeweils was unterschiedliches an srand() übergeben? 
rand() liefert Pseudo -Zufallszahlen, die direkt von dem an srand() 
übergebenen Wert (seed) erzeugt werden! Wenn du srand() mit einem fixen 
Wert aufrufst, kommt bei rand() immer die gleiche Folge raus.

Ralph S. schrieb:
> Weil ld das Linkerprogramm ist ?!?
>
> Ich hab mit beiden gelinkt, mit gcc und mit ld... das gleiche!

Normalerweise linkt man mit "gcc", welcher intern "ld" aufruft und dabei 
automatisch mit der libc und der libgcc linkt, sodass man die nicht mehr 
angeben muss. Für C++ linkt man mit "g++" welches dann auch die 
libstdc++ einbindet.

Ralph S. schrieb:
> Auf seine Art und Weise tut er das, weil er wohl irgendwas aus dem
> Speicher nimmt, nur nicht das was er soll.

Kann eigentlich nicht. Der Linker produziert kein (statisches) Programm 
mit fehlenden Funktionen. Ich tippe darauf, dass alles richtig 
funktioniert und du lediglich srand()/rand() nicht korrekt verwendest...

Ralph S. schrieb:
> Ich nehme mir mal den Assembleroutput vor

Auch eine gute Idee.

PS: In C++ gibt es die <random> Library, welche verschiedene 
Zufallszahlengeneratoren mit unterschiedlichen Eigenschaften bietet, was 
flexibler als rand() ist.

von Ralph S. (jjflash)


Lesenswert?

Programmierer schrieb:
> Und auch hoffentlich jeweils was unterschiedliches an srand() übergeben?
> rand() liefert Pseudo -Zufallszahlen, die direkt von dem an srand()
> übergebenen Wert (seed) erzeugt werden! Wenn du srand() mit einem fixen
> Wert aufrufst, kommt bei rand() immer die gleiche Folge raus.

Weiß ich ...

Programmierer schrieb:
> Normalerweise linkt man mit "gcc", welcher intern "ld" aufruft und dabei
> automatisch mit der libc und der libgcc linkt, sodass man die nicht mehr
> angeben muss. Für C++ linkt man mit "g++" welches dann auch die
> libstdc++ einbindet.

Weiß ich auch, g++ ist hier uninteressant weil plain C ist.

Programmierer schrieb:
> Kann eigentlich nicht. Der Linker produziert kein (statisches) Programm
> mit fehlenden Funktionen. Ich tippe darauf, dass alles richtig
> funktioniert und du lediglich srand()/rand() nicht korrekt verwendest...

Ganz sicher funktioniert NICHT alles korrekt, aber für dich jetzt:

Natürlich habe ich auch CC als Linker versucht:
1
LDFLAGS      = -flto -lm -lgcc -lc -lnosys
2
3
$(CC) $(OBJS) $(LIBSPEC) $(LDFLAGS) -T $(LSCRIPT) -nostartfiles -o $(PROJECT).elf

und der Code im C:
1
  srand(2020);
2
  for (x= 0; x < 150; x++)
3
  {
4
    z= rand();
5
    z= z % 0x7fff;
6
    if ((x % 20) == 0) printf("\n\r");
7
    printf("%d   ",(int16_t) z);
8
  }

Das hier produziert 150 mal den Zahlenwert : 4976

Lasse ich den obigen Code auf AVR laufen (mit der der Toolchain 
zugehörigen libc) oder auf einem STM32 (in Verbindung mit libopencm3) 
oder auf einem MSP430 generiert das obige Programmschnipsel 150 
unterschiedliche Zahlenwerte (die logischerweise beim Programmstart 
immer die gleiche Zahlenfolge hat).

Da das Setup für diesen LPC von mir händisch eingerichtet ist, ist 
sicherlich im Setup ein Fehler und nicht im C-Code an sich (sonst würde 
er nicht auf unterschiedlichen Systemen laufen) ... ein Test auf der 
Konsole erspare ich mir, weil ich mir sicher bin, dass es dort auch 
funktioniert.

Irgendetwas stimmt nicht mit dem Aufruf von rand / lmul ... und 
natürlich bin ich mit dem Assembleroutput noch nicht durch.

Programmierer schrieb:
> In C++ gibt es die <random> Library, welche verschiedene
> Zufallszahlengeneratoren mit unterschiedlichen Eigenschaften bietet

Na ja, ich möchte hier aber kein C++ haben. Auf größeren Controllern 
bisweilen (sehr) gerne, hier aber nicht !

von Programmierer (Gast)


Lesenswert?

Ralph S. schrieb:
> srand(2020);
>   for (x= 0; x < 150; x++)
>   {
>     z= rand();
>     z= z % 0x7fff;
>     if ((x % 20) == 0) printf("\n\r");
>     printf("%d   ",(int16_t) z);
>   }

Kannst du vielleicht einen einfacheren Code ausprobieren? Ich blick 
gerade nicht ganz durch was du mit diesem Modulo und dem Cast machen 
willst. Wie wärs mit:
1
for (int x = 0; x < 150; ++x) {
2
  int z = rand ();
3
  if ((x % 20) == 0) printf("\r\n");
4
  printf ("%d  ", z);
5
}
\n\r ist auch kurios... Nicht dass das dein Terminal-Programm 
durcheinander bringt ;-)

Ralph S. schrieb:
> Ganz sicher funktioniert NICHT alles korrekt, aber für dich jetzt:

Nicht gleich so aggressiv.

Ralph S. schrieb:
> Na ja, ich möchte hier aber kein C++ haben. Auf größeren Controllern
> bisweilen (sehr) gerne, hier aber nicht !

Ist auf einem Cortex-M0 überhaupt kein Problem, aber egal.

Ralph S. schrieb:
> Irgendetwas stimmt nicht mit dem Aufruf von rand / lmul ... und
> natürlich bin ich mit dem Assembleroutput noch nicht durch.

Wenn du den Assembler-Output eines Minimal-Programms mit rand() und 
srand() zeigst (mit zugehörigem C-Code oder gleich ganzem Projekt) kann 
man sich den ansehen.

Deinem Linker-Script mangelt es übrigens dramatisch an 
Alignment-Anweisungen (besonders wichtig für den M0, da der gar kein 
Unaligned kann). Probier mal:
1
MEMORY
2
{
3
    flash : org = 0x00000000, len = 32k
4
    ram   : org = 0x10000000, len = 4k
5
}
6
  
7
SECTIONS
8
{
9
  . = ORIGIN(flash);
10
  .text : 
11
  {
12
     . = ALIGN(4);
13
     KEEP(*(.vectors)); /* The interrupt vectors */
14
     . = ALIGN(4);
15
     *(.text);
16
     *(.text*);
17
     . = ALIGN(4);
18
   } >flash
19
20
  . = ORIGIN(ram);
21
  .data (NOLOAD) : 
22
  {
23
     . = ALIGN(4);
24
    INIT_DATA_VALUES = LOADADDR(.data);
25
    INIT_DATA_START = .;
26
    *(.data);
27
    *(.data*);
28
     . = ALIGN(4);
29
    INIT_DATA_END = .;
30
  } >ram AT>flash
31
32
  .bss (NOLOAD) : 
33
  {
34
     . = ALIGN(4);
35
     BSS_START = .;
36
    *(.bss);
37
    *(.bss*);
38
     . = ALIGN(4);
39
     BSS_END = .;
40
  } > ram
41
}
So kannst du den Startup-Code auch beschleunigen indem du immer 
4-Byte-Werte überträgst.

Außerdem solltest du die Symbole mit einem Unterstrich beginnen, denn 
z.B. "INIT_DATA_VALUES" ist ein gültiger C-Bezeichner und kann somit mit 
normalen C-Symbolen kollidieren; wenn du da z.B. "_INIT_DATA_VALUES" 
draus machst kann das nicht passieren, weil so ein Bezeichner in C 
reserviert ist.

von foobar (Gast)


Lesenswert?

Ich denke, du haust hier was durcheinander.  "__aeabi_lmul" und ähnlich 
benamte Funktionen sind Teil des Compilers und dienen dazu, komplexere 
Funktionen zu implementieren, üblicherweise welche, die die CPU nicht 
direkt kann (hier z.B. eine 64-bit-Multiplikation).  Diese befinden sich 
im libgcc[1] - das libc hat damit nichts zu tun.

Dein Problem wird genauso auch bei z.B.:
1
long long a,b;
2
3
long long foo() { return a*b; }
4
5
int main(int argc, char **argv)
6
{
7
    return foo();
8
}
auftreten.



[1] Das libgcc ist compiler- und mcpu/march/mabi-abhängig - jede Version 
des Compilers hat für jede unterstützte CPU/Architektur/ABI ein eigenes 
libgcc; bei Crosscompilern muß man darauf achten, dass das richtige 
genommen wird!  Der gcc-Frontend macht das normalerweise richtig, beim 
direkten ld-Aufruf muß man sich evtl selbst darum kümmern.

von Ralph S. (jjflash)


Lesenswert?

Programmierer schrieb:
> Kannst du vielleicht einen einfacheren Code ausprobieren? Ich blick
> gerade nicht ganz durch was du mit diesem Modulo und dem Cast machen
> willst.

Das printf ist eine eigene Implementierung... und das verwendete 
Terminal ist ein modifiziertes picocom.

\n\r  trennt im Terminal die newline und das carriage return

So kann ich mit einfachsten Mitteln im Terminal beispielsweise mit

printf("  %.2f V    \r", volt);

sorgen, dass der Cursor nur an den Anfang der Zeile springt und das 
Terminal NICHT scrollt. Somit kann ich eine einfache Ausgabe an immer 
der gleichen Stelle im Terminal machen

\n\r ist demnach eine neue Zeile und ein carriage return (MS-DOS, 
Windows-Style)

Programmierer schrieb:
> was du mit diesem Modulo und dem Cast machen
> willst

den Cast mache ich, weil meine Implementierung von printf nur 
16-Bitwerte akzeptiert... der Modulo soll eben nur Zahlen von 0 bis 
32767 generieren.

Programmierer schrieb:
> Nicht gleich so aggressiv.

Entschuldigung !

foobar schrieb:
> 1] Das libgcc ist compiler- und mcpu/march/mabi-abhängig - jede Version
> des Compilers hat für jede unterstützte CPU/Architektur/ABI ein eigenes
> libgcc; bei Crosscompilern muß man darauf achten, dass das richtige
> genommen wird!

Ich weiß nicht, wie oft ich das jetzt schon kontrolliert habe, ob das 
die richtigen sind.

foobar schrieb:
> Dein Problem wird genauso auch bei z.B.:long long a,b;
>
> long long foo() { return a*b; }
>
> int main(int argc, char **argv)
> {
>     return foo();
> }
> auftreten.

stimmt, tut es.

Programmierer schrieb:
> Deinem Linker-Script mangelt es übrigens dramatisch an
> Alignment-Anweisungen (besonders wichtig für den M0, da der gar kein
> Unaligned kann). Probier mal:

ich werde es ausprobieren

von Ralph S. (jjflash)


Lesenswert?

foobar schrieb:
> Diese befinden sich
> im libgcc[1]

Das werde ich mir jetzt noch einmal sehr viel deutlicher ansehen ... und 
nicht die libc... (allerdings habe ich die was weiß ich schon wie oft 
kontrolliert, ob das auch die des Compilers ist).

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.