Forum: Compiler & IDEs GCCs Divisions-Routinen ersetzen


von N. G. (newgeneration) Benutzerseite


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:
1
int32_t sdiv(int32_t num, int32_t denom);
2
uint32_t udiv(uint32_t num, uint32_t denom);
3
sdiv_t sdivmod(int32_t num, int32_t denom);
4
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:
1
int32_t __aeabi_idiv(int32_t numerator, int32_t denominator);
2
uint32_t __aeabi_uidiv(uint32_t numerator, uint32_t denominator);
3
typedef struct { int32_t quot; int32_t rem; } idiv_return;
4
typedef struct { uint32_t quot; uint32_t rem; } uidiv_return;
5
idiv_return __aeabi_idivmod(int32_t numerator, int32_t denominator);
6
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:
1
int32_t __aeabi_idiv(int32_t numerator, int32_t denominator) {
2
    int32_t (*sdiv)(int32_t, int32_t) = 0x1FFF1FF8 + 0x10 + 0x0;
3
    return sdiv(numerator, denominator);
4
}
5
/* 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.ihi0043d/IHI0043D_rtabi.pdf
**) https://godbolt.org/g/zskz1x

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Vielleicht so?  Hier mit avr-gcc:
1
int a, b;
2
3
int main()
4
{
5
    return a / b;
6
}

Wird zu:
1
0000008a <main>:
2
  ...
3
  9a:  02 d0         rcall  .+4        ; 0xa0 <__divmodhi4>
4
  9c:  cb 01         movw  r24, r22
5
  9e:  08 95         ret
6
7
000000a0 <__divmodhi4>:
8
  a0:  97 fb         bst  r25, 7
9
  ...

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:
1
-Wl,--defsym,__divmodhi4=0x1234
Was dann wird zu:
1
0000008a <main>:
2
  ...
3
  9a:  0e 94 1a 09   call  0x1234  ; 0x1234 <__divmodhi4>
4
  9e:  cb 01         movw  r24, r22
5
  a0:  08 95         ret
6
7
000000a2 <_exit>:
8
  ...
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:
1
-Wl,--wrap,__divmodhi4 -Wl,--defsym,__wrap___divmodhi4=0x1234
1
0000008a <main>:
2
  ...
3
  9a:  0e 94 1a 09   call  0x1234  ; 0x1234 <__wrap___divmodhi4>
4
  ...

von N. G. (newgeneration) Benutzerseite


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.

von N. G. (newgeneration) Benutzerseite


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.
1
$ cat arm-div.c 
2
int main() {
3
    volatile unsigned int a = 5, b = 2;
4
    return a / b;
5
}
1
$ arm-none-eabi-gcc -Wall -Os -mthumb -mcpu=cortex-m0 arm-div.c -nostartfiles -Wl,--defsym,__aeabi_uidiv=0x1234
2
.../ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000
(Warning, weil ich kein eigenes ld-skript angegeben habe. Kann hier 
ignoriert werden)
1
$ arm-none-eabi-objdump -d -S a.out 
2
3
a.out:     file format elf32-littlearm
4
5
6
Disassembly of section .text:
7
8
00008000 <main>:
9
    8000:       2305            movs    r3, #5
10
    8002:       b507            push    {r0, r1, r2, lr}
11
    8004:       9300            str     r3, [sp, #0]
12
    8006:       3b03            subs    r3, #3
13
    8008:       9301            str     r3, [sp, #4]
14
    800a:       9800            ldr     r0, [sp, #0]
15
    800c:       9901            ldr     r1, [sp, #4]
16
    800e:       f7f9 f911       bl      1234 <__aeabi_uidiv>
17
    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.

von Johann L. (gjlayde) Benutzerseite


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

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.