mikrocontroller.net

Forum: Compiler & IDEs GCCs Divisions-Routinen ersetzen


Autor: N. G. (newgeneration) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Hallo Forum,

zur Zeit beschäftige ich mich gezwungenermaßen mit dem LPC824. Die 
gesamte Serie von NXP besitzt sogenannte ROM-APIs. Hauptsächlich dienen 
diese zur Hardware-Ansteuerung.

Speziell dieses Modell hat aber auch "Performance-optimized 
signed/unsigned integer division" Funktionen. Folgende Funktionen sind 
im ROM implementiert:
int32_t sdiv(int32_t num, int32_t denom);
uint32_t udiv(uint32_t num, uint32_t denom);
sdiv_t sdivmod(int32_t num, int32_t denom);
udiv_t udivmod(uint32_t num, uint32_t denom);
Diese liegen an der Adresse 0x1FFF_1FF8 + 0x10 und den darauffolgenden 
Adressen.

Aus der ARM EBAI Beschreibung*) entnehme ich, dass (da es keine 
Divisions-Instruktionen gibt) die folgenden Funktionen aus der libgcc 
aufgerufen werden:
int32_t __aeabi_idiv(int32_t numerator, int32_t denominator);
uint32_t __aeabi_uidiv(uint32_t numerator, uint32_t denominator);
typedef struct { int32_t quot; int32_t rem; } idiv_return;
typedef struct { uint32_t quot; uint32_t rem; } uidiv_return;
idiv_return __aeabi_idivmod(int32_t numerator, int32_t denominator);
uidiv_return __aeabi_uidivmod(uint32_t numerator, uint32_t denominator);

Soweit zu den Gegebenheiten:

Meine Frage ist jetzt, wie ich den GCC dazu bewegen kann, statt den 
Funktionen der libgcc die ROMAPI aufzurufen.

Mein naiver Ansatz wäre so:
int32_t __aeabi_idiv(int32_t numerator, int32_t denominator) {
    int32_t (*sdiv)(int32_t, int32_t) = 0x1FFF1FF8 + 0x10 + 0x0;
    return sdiv(numerator, denominator);
}
/* usw. */
Allerdings werden so ja extra Funktionen, samt extra push/pop-Sequenz, 
generiert, die dann weitere Funktionen anspringen. Diesen extra Sprung 
und das push/pop**) würde ich gerne, wenn es geht, abstellen.

Kann ich dem GCC mitteilen, dass die __aeabi_[ui]div(mod) an speziellen 
Adressen liegen und nicht nochmal dazugelinkt werden müssen? (mglw. mit 
-Wl,--defsym=name=...?)


Mit freundlichen Grüßen,
N.G.

PS:
1. ich weiß nicht, ob die Performance der ROM-API besser ist, ich will 
es aber einfach mal ausprobieren.
2. Ich habe weder ein Performance-, noch ein Speicher-Problem, 
allerdings will ich die Funktion schon mal nutzen, wenn sie angeboten 
wird.

*) 
http://infocenter.arm.com/help/topic/com.arm.doc.i...
**) https://godbolt.org/g/zskz1x

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Vielleicht so?  Hier mit avr-gcc:
int a, b;

int main()
{
    return a / b;
}

Wird zu:
0000008a <main>:
  ...
  9a:  02 d0         rcall  .+4        ; 0xa0 <__divmodhi4>
  9c:  cb 01         movw  r24, r22
  9e:  08 95         ret

000000a0 <__divmodhi4>:
  a0:  97 fb         bst  r25, 7
  ...

Also ähnlich wie bei arm: gcc erzeugt einen lib-Aufruf, hier __divmodhi4 
aus libgcc.  Um stattdessen nach 0x1234 zu springen (wo hier kein 
sinnvoller Code steht) bein Linken:
-Wl,--defsym,__divmodhi4=0x1234
Was dann wird zu:
0000008a <main>:
  ...
  9a:  0e 94 1a 09   call  0x1234  ; 0x1234 <__divmodhi4>
  9e:  cb 01         movw  r24, r22
  a0:  08 95         ret

000000a2 <_exit>:
  ...
D.h. ld löst das Symbol nicht durch Linken gegen libgcc.a auf, sonder 
gemäß der Definition des Symbols von der Kommandozeile.

Symbole können auch im Linker-Skript festgelegt werden, falls das besser 
in den Build-Prozess passt.

Ob das gut mit Symbolreferenzen funktioniert, die sich in anderen 
Bibliotheken oder der libgcc selbst befinden, weiß ich nicht konkret. 
Evtl. hilft es dann, ein anderes Symbol zu verwenden, das nicht in der 
Bibliothek auftaucht:
-Wl,--wrap,__divmodhi4 -Wl,--defsym,__wrap___divmodhi4=0x1234
0000008a <main>:
  ...
  9a:  0e 94 1a 09   call  0x1234  ; 0x1234 <__wrap___divmodhi4>
  ...

Autor: N. G. (newgeneration) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Johann,

danke für deine Antwort.

Dann lag ich ja mit meiner defsym-Idee gar nicht so falsch :-)

Das werde ich probieren, sobald ich die Hardware wieder habe. Dann teste 
ich auch mal die Performance.

Johann L. schrieb:
> Symbole können auch im Linker-Skript festgelegt werden, falls das besser
> in den Build-Prozess passt.

Ja, das wäre mir lieb, da ich (ARM-typisch) sowieso ein eigenes 
ld-Skript nutze. Wie müsste ich so etwas machen (ich tippe auf 
PROVIDE())?

Johann L. schrieb:
> Ob das gut mit Symbolreferenzen funktioniert, die sich in anderen
> Bibliotheken oder der libgcc selbst befinden, weiß ich nicht konkret.
> Evtl. hilft es dann, ein anderes Symbol zu verwenden, das nicht in der
> Bibliothek auftaucht

Inwiefern könnte es da Probleme geben, und wie würden die sich äußern? 
Link-time-errors oder ein nicht-funktionierendes Programm?

Mit freundlichen Grüßen,
N.G.

Autor: N. G. (newgeneration) Benutzerseite
Datum:

Bewertung
1 lesenswert
nicht lesenswert
N. G. schrieb:
> Johann L. schrieb:
>> Ob das gut mit Symbolreferenzen funktioniert, die sich in anderen
>> Bibliotheken oder der libgcc selbst befinden, weiß ich nicht konkret.
>> Evtl. hilft es dann, ein anderes Symbol zu verwenden, das nicht in der
>> Bibliothek auftaucht
>
> Inwiefern könnte es da Probleme geben, und wie würden die sich äußern?
> Link-time-errors oder ein nicht-funktionierendes Programm?

Okay, scheinbar geht es sowohl mit (war zu erwarten), als auch ohne 
--wrap.
$ cat arm-div.c 
int main() {
    volatile unsigned int a = 5, b = 2;
    return a / b;
}
$ arm-none-eabi-gcc -Wall -Os -mthumb -mcpu=cortex-m0 arm-div.c -nostartfiles -Wl,--defsym,__aeabi_uidiv=0x1234
.../ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000
(Warning, weil ich kein eigenes ld-skript angegeben habe. Kann hier 
ignoriert werden)
$ arm-none-eabi-objdump -d -S a.out 

a.out:     file format elf32-littlearm


Disassembly of section .text:

00008000 <main>:
    8000:       2305            movs    r3, #5
    8002:       b507            push    {r0, r1, r2, lr}
    8004:       9300            str     r3, [sp, #0]
    8006:       3b03            subs    r3, #3
    8008:       9301            str     r3, [sp, #4]
    800a:       9800            ldr     r0, [sp, #0]
    800c:       9901            ldr     r1, [sp, #4]
    800e:       f7f9 f911       bl      1234 <__aeabi_uidiv>
    8012:       bd0e            pop     {r1, r2, r3, pc}
Funktioniert also.
Die Performance habe ich mangels Hardware noch nicht testen können.

Die Frage nach der Angabe im Linker-Skript bleibt aber noch bestehen ;-)

Mit freundlichen Grüßen,
N.G.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
N. G. schrieb:
> Die Frage nach der Angabe im Linker-Skript bleibt aber noch bestehen ;-)

Für die genaue Syntax müsste ich auch erst die Doku konsultieren:

https://sourceware.org/binutils/docs-2.29/ld/Scripts.html

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.