Alignment des ARM7

Gast #448365
Lesenswert?

Hallo zusammen,

ich bin gerade bei meiner Bachelor Arbeit und muss eine bestehende 
Software auf einem Keil Board zum laufen bringen (fürs erste). 
Funktioniert auch alles bisher ganz gut. Das Board ist ein MCB2140 
(LPC2148) von Keil und Bestandteil des hitex StarterKits.

Jetzt ist es so, dass ich in dem Programm ( C ) auf dem Controller von 
einer Funktion ein Struct zurückbekommen sollte. Bekomm ich aber nicht, 
sondern nur den ersten Teil dieses structs. Das aber nur so nebenbei.

Mein Chef meinte, das alles liegt am alignement des Prozessors. Habe 
mich jetzt auch ein wenig eingelsen, was alignement angeht und weiss 
jetzt schonmal was das ist :)

Jetzt muss ich rausfinden wie das alignment auf dem Stack ist und mit 
dem vergleichen, für den dieses Programm urspürnglich geschrieben wurde. 
Weiss vielleicht jemand wie das bei dem ARM7 Prozessor ist?

Grüße
Nils
Gast #448382
Lesenswert?

Sorry, leider bin ich ganz neu im C Geschäfft, aber ich versuche mal so 
viel ich weiss zu beantworten. Da fällt mir aber gerade auf, dass ich 
nur den Compiler kenne: arm-hitex-elf-gcc.

Vielleicht würde es mir schon helfen, wenn jemand weiss, wie das 
alignment des LPC2148 ist, dann kann ich weiter googlen.
Gast #448496
Lesenswert?

OK jetzt hab ich was:

typedef struct
{
  UInt  uiLength;    /* Current length of flex string */
  Char  charData[8]; /* Content of string */
} FlexString8;

typedef struct
{
  FlexString8  Name;
  FlexString4  Version;
} DeviceIdent_Struct;

USInt usiOffset1 = offsetof ( DeviceIdent_Struct, Version ); // 0x0C
USInt usiOffset2 = offsetof ( FlexString8, charData ); // 0x02
USInt usiOffset3 = sizeof(FlexString8); // 0x0C
USInt usiOffset4 = sizeof(UInt); // 0x02
USInt usiOffset5 = sizeof(Char); // 0x01
USInt usiOffset6 = sizeof(Char[8]); // 0x08

Nur weiss ich jetzt zb.B. leider nicht, wie die sizeOf( FlexString) 
zustande kommt. Eigentlich müsste die doch 10 sein und nicht 12. Liegt 
das am Alignment des Controllers?

Unter welchen Umständen schmeisst der mir noch 2 "Füllbytes" in die 
Länge mit rein?

Grü0e Nils
Gast #448502
Lesenswert?

Der Compiler macht da wohl ein Word-Alignment. In dem Fall ist die
Lücke zwischen uiLength und charData.

Versuche es doch mal damit:

typedef struct
{
  UInt  uiLength;    /* Current length of flex string */
  Char  charData[8]; /* Content of string */
} __attribute__((packed)) FlexString8;

Wobei ich nicht weiß inwieweit der Arm7 das unterstützt.
Der Zugriff auf Daten im Speicher ist bei manchen Prozessoren
schneller wenn diese (Daten) an Wortgrenzen ausgerichtet sind.

 - Michael
Gast #448557
Lesenswert?

hallo nils,
ja der arm benötigt ein alignment, abhängig von der größe der variable 
auf die er zugreifen soll.
16 bit variable (im arm jargon "half word") müssen auf durch 2 teilbare 
adressen beginnen.
32 bit variable (im arm jargon "word") müssen auf durch 4 teilbare 
adressen beginnen.
dies weiss der compiler natürlich und füllt deine struktuiren 
entsprechend auf. kritisch istr bei manchen compilern aber der sizeof 
operatir da dieser ev. die füll-bytes nicht berücksichtigt.
ich würde dir empfehlen das auffüllen selbst zu machen und die 
strukturen entsprechend zu definieren.

gruss
gerhard
Gast #448586
Lesenswert?

Schonmal vielen Dank,

das _attribute_ ((packed)) hat leider nicht geholfen, die Länge meines 
FlexStrings ist immer noch 12.

#pragma pack(1)

hab ich auch versuch, ging auch nicht.

Aber wo packt der denn seine Füllbytes bei dem FlexString rein?

Wenn

USInt usiOffset2 = offsetof ( FlexString8, charData );

gleich 2 ist, dann müsste er sie doch hinter die charData einbauen oder?


Gast #448597
Lesenswert?

Stümmt, darauf habe ich nicht geachtet. Das 'packed' bringt
dann so oder so nichts.
Vom Padding am Ende einer Struktur habe ich noch nie gehört.

Ich habe seit zwei Tagen ein 2148 Board. Der UART geht inzwischen,
sodaß ich das mal mit meiner GCC Version (4.1.1) probieren kann.

Geht aber erst heute Abend.

 - Michael
Gast #448601
Lesenswert?

Möglicherweise hilft das packed-attribute schon - aber nur teilweise. 
Wenn recht erinnert, wird vom gnu C-Compiler dann auch das 
character-array "unmittelbar" hinter dem Längen-Integer angeordnet aber 
am Ende wieder auf "grade" Wordadresse aufgefüllt. #pragma pack dürfte 
das Gleiche auslösen (ich habe pragmas bei gcc noch nie genutzt). In der 
"untersten Ebene" für Flexstring würde attribute packed dann hilfreich 
sein, aber eine Ebene drüber bei DeviceIdent nicht mehr. Das Ganze 
entspricht ja den bisherigen Erkenntnissen. Lässt sich aber auch gut 
testen, in dem man einen uint8_t* auf die Startadresse eines Objekts der 
Struktur zeigen lässt ("casten") und dann Byte für Byte ausgibt 
"cout(*p++)" (oder per Debugger anschaut), dann Elemente ändern und 
wieder Bytestream anschauen. Der tatsächliche Offset wird dann gut 
erkennbar.

Aber diese Art der Zugriffs auf Elemente ist nicht wirklich gut, 
insbesondere wenn aligments zur Optimierung des Speicherzugriffs im 
Spiel sind. Man läd sich - wie schon gemerkt - neue Sorgen auf. Besser 
wäre es Code zu schreiben, der die einzelnen Elemente eines Objekts aus 
der Struktur in ein Bytearray schreibt, bzw. aus einem Bytearray den 
Inhalt für die Elemente ausliest (Serializer/Deserializer). Vielleicht 
etwas langsamer aber dafür problemloser.
Gast #448758
Lesenswert?

So, ich habe mal den GNUARM Compiler v4.1.1 angeworfen:

typedef struct {
  char a;         // 1 Byte
  int  b;         // 4 Bytes
  short c;        // 2 Bytes
  char str[8];  // 8 Bytes
} testObj;

Ergebnis:

sizeof(testObj) = 20
offsetof(a)     = 0
offsetof(b)     = 4
offsetof(c)     = 8
offsetof(str)   = 10

Und:

typedef struct {
  char a;         // 1 Byte
  int  b;         // 4 Bytes
  short c;        // 2 Bytes
  char str[8];  // 8 Bytes
} __attribute__((packed)) testObj;

mit dem Ergebnis:

sizeof(testObj) = 15
offsetof(a)     = 0
offsetof(b)     = 1
offsetof(c)     = 5
offsetof(str)   = 7

Der ARM7 ist also offenbar nicht auf ein Alignment angewiesen, auch
wenn es schneller sein mag.
Wo die zwei Bytes am Ende der "von Nils'schen" Struktur herkommen
kann ich mir nicht erklären.

Da 'UInt' anscheinend nur zwei Bytes groß ist, handelt es sich bei der
Struktur wohl um eine Schnittstelle für Daten die von Außen angeliefert
werden. Stimmts ? ;)

 - Michael
Gast #448842
Lesenswert?

Der ARM7 ist sehr wohl auf Alignment angewiesen. Ein 32bit-Load mit A0:1 
!=0 wird zwar nicht auf die Nase fallen, aber auch nicht das tun, was 
man davon vielleicht erwartet.

Nur erzeugt der Compiler in solchen Fällen Code, der auch ohne Alignment 
auskommt. Bei Bitfields geht es ja auch.
Gast #448857
Lesenswert?

^ Ich dachte mir schon das meine Aussage etwas voreilig war und habe
mir mal die .lst-Datei angesehen. Der Compiler schiebt die Daten in
der Tat passend zurecht.

Der GCC beeindruckt mich immer wieder. Ich mußte die Codeoptimierung
abschalten damit auch tatsächlich auf 'obj' zugegriffen wird.
Sonst hat der Compiler für rprintf() einfach die Konstanten eingesetzt:
1
typedef struct {
2
  char a;
3
  char b;
4
  char c;
5
  short size;
6
} __attribute__((packed)) stype;
7

8
    obj.a = 1;
9
    obj.b = 2;
10
    obj.c = 3;
11
    obj.size = sizeof(stype);
12
    
13
    rprintf("a=%u, b=%u, c=%u, size=%u\n", obj.a, obj.b, obj.c, obj.size);

 - Michael

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren