Forum: Compiler & IDEs Wie auf C-struct elemente in assembler function zugreifen


von Friedrich S. (fseuhs)


Lesenswert?

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
von Markus F. (mfro)


Lesenswert?

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...

von Dr. Sommer (Gast)


Lesenswert?

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?

von Amateur (Gast)


Lesenswert?

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.

von Friedrich S. (fseuhs)


Lesenswert?

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.

von Dr. Sommer (Gast)


Lesenswert?

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?!

von Friedrich S. (fseuhs)


Lesenswert?

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.

von Mark 99 (Gast)


Lesenswert?

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.

von sep (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.