Ich habe fogendes Problem: In einem C.header-file definiere ich eine struct und einen Functionprototyp Da sich die struct ändern kann möchte ich im assembler über entsprechende namen zugreifen können. Z.B. myfile.h struct mystruct { int data1; int *data2; char *text; }; int myassemblerfunction(struct mystructure *mstr); Im zugehörigen C-file verwende ich diese structur wie folgt myfile.c // variable definieren #include myfile.h int i1; int i2[32]; char t = "Ein Text"; // Variabler meiner struct struct mystruct mst; // Mit Werten füllen, die im assembler verwertet werden mst.data1 = i1; mst.data2 = i2; mst.text = t; // Aufruf der assemblerfunktion myassemblerfunction(&mst); In der ARM-assembler file möchte ich das so oder ähnlich verwenden: myfile.S .global myassemblerfunction myassemblerfunction: ldr r1,[r0, #data1] ldr r2,[r0, #data2] ldr r3,[r0, #text] Hilfreich wäre es auch wenn ich im assembler eine äquivalente function zu sizeof(data2) verwenden könnte.
:
Bearbeitet durch User
Die Syntax zwischen verschiedenen Toolchains differiert stark, was Inline-Assembler angeht (da wäre, was Du machen willst, m.E. am einfachsten zu realisieren). Wenn der Code in separaten Files steht (also nicht inline, so wie bei dir) hängt die Parameterüberabe und das Alignment vom verwendeten ABI, Prozessor (ARM, habe ich verstanden) und auch vom verwendeten Compiler ab. Man wird dir also wesentlich einfacher helfen können, wenn Du den beim Namen nennst...
Der Assembler weiß leider nichts von C-Dingen wie structs. Falls du GCC verwendest, kannst du die Inline Assembler Constraints verwenden, um C-Daten zu übergeben; dazu lässt man sich vom C-Compiler den Assemblercode automatisch so anpassen, dass er eben zB auf das struct-Layout passt:
1 | void myassemblerfunction () { |
2 | asm volatile ("add r0, %0, %1" : : "r" (mst.data1), "r" (mst.data2)); |
3 | }
|
Hier sucht sich der Compiler zwei Register aus (zB r5, r6) und ersetzt im Assembler-Code das %0 und %1 durch diese. Dann generiert er vor die "asm" Anweisung Code, der die 32bit-Daten mst.data1 und mst.data2 in eben diese Register lädt. So kannst du dann im Assembler-Code auf die Daten zugreifen, im Beispiel sie addieren. Das funktioniert im Übrigen auch wenn mst.data1 keine feste Adresse hat, zB wenn "mst" ein Parameter wäre. Es gibt noch andere Möglichkeiten, zB sich die Adresse vom "mst.data1" vom Compiler berechnen zu lassen und diese in ein "ldr" zu übergeben. Hier ein paar sehr hilfreiche Seiten bzgl. GCC Inline Assembly: http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#ss5.3 http://www.ethernut.de/en/documents/arm-inline-asm.html http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/ GCC Inline Assembly korrekt zu verwenden ist etwas tricky, es gibt da diverse Fallen durch die Optimierung, zB wenn man sich temporäre- und Input-Register geben lässt und die sich überschneiden könnten... Bei ARM (zumindest ARMv7) braucht man allerdings kaum Assembler, da (fast) alles in C machbar ist. Daher solltest du dir vielleicht überlegen ob du unbedingt Assembler brauchst?
Zusammen mit den GNU-Bibliotheken gibt es einiges an Hilfe(-dateien). U. a. auch wie man Assembler und C mischt sowie welche Register in C verwendet werden. Ersteres mit Beispielen.
Meine Toolchain ist Crossworks für Arm von Rowley im speziellen für den ARM Cortex M4. Dr. Sommer schrieb: > Bei ARM (zumindest ARMv7) braucht man allerdings kaum Assembler, da > (fast) alles in C machbar ist. Daher solltest du dir vielleicht > überlegen ob du unbedingt Assembler brauchst? Ein Hobbyprojekt von mir ist ein forth für den Cotex M4 inklusive floating point. Das habe ich halt als extra assembler file angelegt. Wobei das meiste automatisch generiert wird, aber als Ziel ist ein Assembler file. Das ganze nach inline assembler umzubauen, wäre zwar möglich, müsste aber alles ändern.
Friedrich Seuhs schrieb: > Meine Toolchain ist Crossworks für Arm von Rowley im speziellen für den > ARM Cortex M4. Laut Website verwendet das auch nur den GCC. Friedrich Seuhs schrieb: > Das ganze nach inline assembler umzubauen, wäre zwar > möglich, müsste aber alles ändern. Wo ist das Problem? Nach .c umbenennen und C-Funktionsheader sowie "asm volatile" dranschreiben sollte doch machbar sein. Zumindest für die fraglichen Funktionen. Und da man wie gesagt fast alles in C machen kann sollte es an Assembler-Funktionen onehin nicht so viele geben?!
Dr. Sommer schrieb: > Wo ist das Problem? Nach .c umbenennen und C-Funktionsheader sowie "asm > volatile" dranschreiben sollte doch machbar sein. Zumindest für die > fraglichen Funktionen. Und da man wie gesagt fast alles in C machen kann > sollte es an Assembler-Funktionen onehin nicht so viele geben?! Ich verwende auch assembler macros. Viele der Register r0-r14 haben eine spezielle fixe Funktion und werden mit equates unter anderen für forth sinnvolle Namen verwendet. Da ich Hauptaugenmerk auf die Geschwindigkeit gelegt habe, gibt es doch einige Assemblerfunktionen. Danke einmal für Deinen inline-Vorschlag, damit versuche ich forth zu starten und die Struct inline zu übergeben, alles weiter geht dann sowieso im Assembler.
Eigentlich müsste das fast mit Standard-C gehen. Ich habe gerade keinen Compiler zur Hand, also nur ein paar Fragmente:
1 | typedef struct { |
2 | int i; |
3 | char *s; |
4 | } S; |
5 | |
6 | size_t off_i = offsetof(S, i); |
7 | size_t off_s = offsetof(S, s); |
8 | |
9 | S test; |
Im Assemblercode dann die die Werte der Symbole off_i und off_s auslesen und auf die jeweilige Anfangsadresse, z.B. die Adresse von test, addieren.
Hey, So was in der Art habe ich auch schon mal gehabt. Hatte einige Zeit gesucht und dann was feines gefunden. Den direkten Link finde ich nicht mehr. Aber ich hab das noch hier zu liegen. Ich hab mir eine Datei namens stk500_structs_offset.c erstellt.
1 | #include <stddef.h> |
2 | #include "protocol/stk500_frame.h" |
3 | |
4 | #define _ASMDEFINE( sym, val ) asm volatile \
|
5 | ( "\n#define " #sym " %0 \n" : : "i" ( val ) )
|
6 | |
7 | #define ASMDEFINE( s, m ) \
|
8 | _ASMDEFINE( asm_##s##_##m, offsetof( s, m ) )
|
9 | |
10 | #define _ASMDEFINESIZE( sym, val ) asm volatile \
|
11 | ( "\n#define " #sym " %0 \n" : : "i" ( val ) )
|
12 | |
13 | #define ASMDEFINESIZE( s ) \
|
14 | _ASMDEFINESIZE( asm_##s##_size, sizeof( s ) )
|
15 | |
16 | stk500_defineOffsets() { |
17 | ASMDEFINESIZE( stk500_frame ); |
18 | ASMDEFINE( stk500_frame, seqNr ); |
19 | ASMDEFINE( stk500_frame, msgSize ); |
20 | ASMDEFINE( stk500_frame, buf ); |
21 | |
22 | ASMDEFINESIZE( stk500_manage ); |
23 | ASMDEFINE( stk500_manage, state ); |
24 | ASMDEFINE( stk500_manage, lastSeq ); |
25 | ASMDEFINE( stk500_manage, chkSum ); |
26 | ASMDEFINE( stk500_manage, msgSize ); |
27 | }
|
Mithilfe des Makefile wird dann eine Datei generiert. Das geht wie folgt:
1 | @$(CC) $(INCLUDES) -S $(@:.h=.c) -o - | grep \#define > "$@" |
Somit habe ich dann am Ende eine Datei die ich einfach ins *.S File einbinden kann. Dort habe ich dann die Größe und die Offsets der strukturen.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.