Forum: Compiler & IDEs memcpy auf ARM Cortex A9 & Linaro


von olpo (Gast)


Lesenswert?

Hallo zusammen,


ich habe ein Programm, das memcpy verwendet.
Allerdings stuerzt das Programm ab, was, glaube ich, an "region overlap" 
bei der Funktion memcpy() liegt.
1
memcpy(80006e80, 80006e84, 4):

Da ein "region overlap" bei memcpy() zu Problemen fuehren kann, soll man 
wohl eher memmove() verwenden.
Ich habe ebenfalls gelesen, dass die meisten Prozessoren oder Compiler 
memcpy() wie memmove() behandeln, um solch ein Laufzeitfehler 
auszuschliessen.

Ich benutze einen ARM Cortex A9 und Linaro-gcc.
Hier wird leider nichts wegoptimiert und ich laufe ich den Fehler.

Ich habe hier legacy SW, die ich nur ungern veraendern moechte.

Weiss jmd ob ich Compiler-Flags setzen kann, die mir das Problem loesen?
Oder muss ich fuer diese Plattform den Code umschreiben?


DANKE!

von user (Gast)


Lesenswert?

wie wäre es mit einem #define

#define memcpy memmove

oder beim gcc Aufruf

gcc -Dmemcpy=memmove

von Markus F. (mfro)


Lesenswert?

Das Verhalten von memcpy() ist bei überlappenden Speicherbereichen 
tatsächlich undefiniert.

olpo schrieb:
> memcpy(80006e80, 80006e84, 4):

Hier kann ich allerdings beim besten Willen keine Überlappung erkennen - 
memmove() wird da nichts besser machen, würde ich mal unterstellen.

von PittyJ (Gast)


Lesenswert?

Ich habe das hier mal auf einem ARM mit Linaro-Compiler getestet.

Das Programm macht exakt das, was es soll. Der memcpy() funktioniert. 
Die richtigen Bytes werden kopiert. Nichts stürzt ab.

Von daher glaube ich nicht an ein memcpy Problem. Zumal memcpy ja in 
tausenden Programmen benutzt wird.
Ich denke mehr, dein Problem liegt in den Zeilen, die du hier nicht 
gepostet hast.

von Markus F. (mfro)


Lesenswert?

PittyJ schrieb:
> Das Programm macht exakt das, was es soll. Der memcpy() funktioniert.
> Die richtigen Bytes werden kopiert. Nichts stürzt ab.
>
Der einzige Unterschied zwischen memcpy() und memmove() ist der, daß 
Letzteres vor dem Kopieren auf Überlappung der Speicherbereiche prüft 
und entsprechend "aufwärts" oder "abwärts" kopiert, um sich nicht selbst 
die Quelle zu überschreiben.

Da hier nichts überlappt, macht es keinen Unterschied (außer, daß 
memmove() hier unnötigerweise ein klein wenig langsamer ist).

von (prx) A. K. (prx)


Lesenswert?

Ich kann überdies auch keinen Grund erkennen, weshalb memcpy bei 
Überlappung die Grätsche machen sollte, so hier eine gewesen wäre. Es 
kommt bloss nicht unbedingt das raus, was man haben will.

von Markus F. (mfro)


Lesenswert?

A. K. schrieb:
> Ich kann überdies auch keinen Grund erkennen, weshalb memcpy bei
> Überlappung die Grätsche machen sollte, so hier eine gewesen wäre. Es
> kommt bloss nicht unbedingt das raus, was man haben will.

Wenn wir schon dabei sind: manchmal bin ich mir nicht sicher, ob 
bestimmte Fragen wirklich so ernst gemeint sind, wie's auf den ersten 
Blick aussieht.

Ich persönlich käme beispielsweise nicht unbedingt (zumindest nicht auf 
einem 32-bit Dualcore) auf die Idee, ein - offensichtlich perfekt 
ausgerichtetes - int per memcpy() zu kopieren oder vielleicht doch 
lieber per memmove(), weil es sich ja selber überlappen könnte.

Ein einfaches
1
* (int *) 0x80006e80 = * (int *) 0x80006e84;

würde hier ohne große Diskussion dasselbe (richtige) tun, bloß viel 
schneller...

von Peter II (Gast)


Lesenswert?

Markus F. schrieb:
> Ein einfaches
> * (int *) 0x80006e80 = * (int *) 0x80006e84;
>
> würde hier ohne große Diskussion dasselbe (richtige) tun, bloß viel
> schneller...

und da bist du dir sicher? Eventuell wird ja erst ins Register geladen, 
dann wieder an die neue stelle geschrieben.

beim memcopy kann es die cpu direkt im ram machen.

Ich finde memcopy hier besser und lesbarer.

von Markus F. (mfro)


Lesenswert?

Lach! 8-)

Dann werde ich künftig keine direkten Zuweisungen in der Form
1
int i = 4711;

mehr machen (ist ja irgendwie auch viel zu einfach). Bloß noch:
1
int i;
2
const int c = 4711;
3
4
memcpy(&i, &c, sizeof(int));

Ist ja auch viel lesbarer. Wenn's hilft...

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Markus F. schrieb:
> Lach! 8-)
>
> Dann werde ich künftig keine direkten Zuweisungen in der Form
> int i = 4711;
>
> mehr machen (ist ja irgendwie auch viel zu einfach). Bloß noch:
> int i;
> const int c = 4711;
>
> memcpy(&i, &c, sizeof(int));
>
> Ist ja auch viel lesbarer. Wenn's hilft...

einmal sind es variabel die schon im Register sind, einmal ist es nur 
RAM. Das ist der unterschied.

Außerdem würde memcpy auch auf 8 und 16bit cpus laufen, ohne das man 
etwas ändern muss.

von Markus F. (mfro)


Lesenswert?

Wir kommen jetzt ein wenig ins philosophische. Ich bin kein 
ARM-Spezialist, aber wenn ich micht nicht ganz täusche, kennt die 
ARM-Plattform keine Addressierungsart memory-to-memory. Da ist immer ein 
Register beteiligt.

von Klaus W. (mfgkw)


Lesenswert?

klar, daß memcpy auch nicht zaubern kann.
Besser als ein guter Compiler mit Codeoptimierung wird die Funktion 
nicht sein können...

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> beim memcopy kann es die cpu direkt im ram machen.

Nicht bei einem ARM. Mem->Mem hat der nicht.

Und bei x86 ist es eine hochkomplexe Angelegenheit, zu bestimmen, wann 
auf welchem Prozessor bei welcher Datenmenge welche Kopierversion 
schneller ist.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Klaus Wachtler schrieb:
> Besser als ein guter Compiler mit Codeoptimierung wird die Funktion
> nicht sein können...

Es gibt ein paar Optimierungsmöglichkeiten, die einem Optimizer nicht so 
recht liegen, wie breite SIMD Register, Cache Optimierung, Prefetch etc.

von Rolf M. (rmagnus)


Lesenswert?

Markus F. schrieb:
> Ich persönlich käme beispielsweise nicht unbedingt (zumindest nicht auf
> einem 32-bit Dualcore) auf die Idee, ein - offensichtlich perfekt
> ausgerichtetes - int per memcpy() zu kopieren oder vielleicht doch
> lieber per memmove(), weil es sich ja selber überlappen könnte.
>
> Ein einfaches
> * (int *) 0x80006e80 = * (int *) 0x80006e84;
>
> würde hier ohne große Diskussion dasselbe (richtige) tun, bloß viel
> schneller...

Warum sollte das schneller sein? Vermutlich wird der Code genau der 
selbe sein. Zumindest auf dem x86 ist er es.

von (prx) A. K. (prx)


Lesenswert?

Rolf Magnus schrieb:
> Warum sollte das schneller sein? Vermutlich wird der Code genau der
> selbe sein. Zumindest auf dem x86 ist er es.

Nur wenn der Compiler sich wie GCC die Mühe macht, die Funktionalität 
von memcpy zu kennen und ggf. selbst zu implementieren. Ruft er hingegen 
unabhängig von Randbedingungen einfach nur ebendiese Lib-Funktion auf, 
wird die explizite Umgehung von memcpy bei wenigen Bytes stets erheblich 
schneller sein.

Auch bei grossen Datenmengen war und ist es trotz prozessorspezifischer 
Implementierung per Microcode über die Generationen der Prozessoren 
hinweg keineswegs selbstverständlich, dass der REP MOVS Befehl den 
schnellsten Weg darstellt. Erst recht nicht, wenn der Programmierer über 
den Kontext des Transfers mehr weiss, als es Compiler/Microcode können.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Mein m68k-gcc z.B. hat offensichtlich Befürchtungen, daß die Adresse 
auch ungerade sein könnte und kopiert (mit -O3) bei memcpy() 
(__builtin_memcpy()) lieber vier Einzelbytes als ein int.

Mit -ffrestanding (nicht ganz unsinnvoll bei embedded Controllern) ist 
er ganz vorsichtig und ruft auch mit -O3 lieber memcpy() auf (wie sich 
das in dem Fall gehört).

von (prx) A. K. (prx)


Lesenswert?

Markus F. schrieb:
> Mein m68k-gcc z.B. hat offensichtlich Befürchtungen, daß die Adresse
> auch ungerade sein könnte und kopiert (mit -O3) bei memcpy()
> (__builtin_memcpy()) lieber vier Einzelbytes als ein int.

Hängt davon ab, wieviele Parameter der Programmierer des Compilers bei 
der Optimierung des Builtins berücksichtigt.

von Markus F. (mfro)


Lesenswert?

A. K. schrieb:
> Hängt davon ab, wieviele Parameter der Programmierer des Compilers bei
> der Optimierung des Builtins berücksichtigt.

... oder anders gesagt davon, für wie wichtig es eben jener erachtet, 
einen memcpy()-Aufruf, der eigentlich ein int kopiert, soweit zu 
optimieren, daß er nur noch ein int kopiert (mir persönlich wär' offen 
gestanden lieber, er würde seine Kreativität an ein paar anderen, 
realeren Optimierungsfällen auslassen).

Womit wir wieder am Anfang der Schleife wären ;-).

von casud (Gast)


Lesenswert?

Manchmal macht memcpy für 4 bytes sehr wohl Sinn, nämlich dann wenn man 
"type punning" machen will.

Folgender Code ist böse!
1
float f(unsigned *p)
2
{
3
    return *(float *)p;
4
}

Dieser dagegen tut was er soll.
(voraussgesetzt sizeof(float) == sizeof(unsigned))
In den meisten Fällen wird das memcpy wegoptimiert.
1
float f(unsigned *p)
2
{
3
    float fl;
4
    memcpy(&fl, p, sizeof(fl))
5
    return fl;
6
}

von Daniel A. (daniel-a)


Lesenswert?

casud schrieb:
> Manchmal macht memcpy für 4 bytes sehr wohl Sinn, nämlich dann wenn man
> "type punning" machen will.

Dafür gibt es aber bereits unions:
1
float f(unsigned x){
2
  union { 
3
    unsigned u;
4
    float f;
5
  } c;
6
  c.u=x;
7
  return f;
8
}

Oder darf der compiler dass wegen der aliasing rule wegobtimieren?

von Rolf M. (rmagnus)


Lesenswert?

A. K. schrieb:
> Rolf Magnus schrieb:
>> Warum sollte das schneller sein? Vermutlich wird der Code genau der
>> selbe sein. Zumindest auf dem x86 ist er es.
>
> Nur wenn der Compiler sich wie GCC die Mühe macht, die Funktionalität
> von memcpy zu kennen und ggf. selbst zu implementieren.

Ja. Wir reden hier ja auch über GCC. Inwieweit das andere Compiler auch 
machen, weiß ich nicht.

> Auch bei grossen Datenmengen war und ist es trotz prozessorspezifischer
> Implementierung per Microcode über die Generationen der Prozessoren
> hinweg keineswegs selbstverständlich, dass der REP MOVS Befehl den
> schnellsten Weg darstellt. Erst recht nicht, wenn der Programmierer über
> den Kontext des Transfers mehr weiss, als es Compiler/Microcode können.

Das hat dann aber nichts mit der Frage zu tun, ob eine Zuweisung 
schneller ist als ein memcpy. Einige Programme auf dem PC, die große 
Datenmengen im Speicher schnell kopieren müssen, machen beim Start 
Performance-Tests, um zu ermitteln, welche Variante die schnellste ist. 
Gerade auf dem PC gibt es etliche verschiedene Möglichkeiten. REP MOVS 
ist schon lange nicht mehr die schnellste.

Markus F. schrieb:
> Mein m68k-gcc z.B. hat offensichtlich Befürchtungen, daß die Adresse
> auch ungerade sein könnte und kopiert (mit -O3) bei memcpy()
> (__builtin_memcpy()) lieber vier Einzelbytes als ein int.

Welche Adresse? Oben wird die Adresse ja direkt als Zahl angegeben. Daß 
die nicht ungerade sein kann, sollte der Compiler eigentlich erkennen 
können.

> Mit -ffrestanding (nicht ganz unsinnvoll bei embedded Controllern) ist
> er ganz vorsichtig und ruft auch mit -O3 lieber memcpy() auf (wie sich
> das in dem Fall gehört).

Das ist auch der große Nachteil von -ffreestanding. Es unterbindet 
einige Optimierungen, da der Compiler nicht mehr davon ausgehen darf, 
daß sich Funktionen wie memcpy() so verhalten, wie das in ISO-C 
festgelegt ist.

Daniel A. schrieb:
> casud schrieb:
>> Manchmal macht memcpy für 4 bytes sehr wohl Sinn, nämlich dann wenn man
>> "type punning" machen will.
>
> Dafür gibt es aber bereits unions:

Nein, genau dafür sind sie nicht gedacht. Du darfst in C eigentlich nur 
das Union-Element lesen, das du als letztes geschrieben hast. Davon 
abgeshen sieht es meiner Meinung nach auch nicht sonderlich elegant und 
eher umständlich aus, sich extra einen Typ und eine Variable definieren 
zu müssen und dann die Daten da rein und wieder rauszukopieren.

von Markus F. (mfro)


Lesenswert?

Rolf Magnus schrieb:
> Welche Adresse? Oben wird die Adresse ja direkt als Zahl angegeben. Daß
> die nicht ungerade sein kann, sollte der Compiler eigentlich erkennen
> können.

Haha, tut er aber nicht, der blöde Hund.

Die Einzelbytekopiererei wird erst dann durch eine schnelle int-Kopie 
ersetzt, wenn -mno-strict-align in der Kommandozeile steht.

Dann allerdings auch, wenn explizit von/auf ungerade Adressen kopiert 
wird (der Adressfehler-Handler wird's schon richten). :-o

Kenne deinen Compiler - jetzt hab' ich auch was gelernt ;)

von olpo (Gast)


Lesenswert?

Hallo,

kann das etwas mit der Byte-Reihenfolge zu tun haben?

Also ich kompiliere auf einer Intel Little-Endian Maschine.
Das ganze laeuft dann auf ARMv7 mit einem BareMetalOS, bei dem ich mir 
nicht sicher bin, ob das nicht doch Big-Endian kompiliert wurde.
Oder wird __BYTE_ORDER zur Laufzeit und nicht vom Compiler festgelegt?

Zumindest kriege ich keinen Error, wenn ich Little-Endian unten 
auskommentiere.

Das verwirrt mich alles...
1
static inline void store32(unsigned char *const buffer,
2
                           int offset,
3
                           uint32_t value)
4
{
5
    int i;
6
    for (i = 3; i >= 0; i--) {
7
        buffer[offset+i] = (value & 0xff);
8
        value >>= 8;
9
    }
10
}
11
12
#if __BYTE_ORDER == __LITTLE_ENDIAN
13
# define STORE32N(buffer,offset,value)   { printf("Little Endian\n"); memcpy(&buffer[offset], &value, 4); }
14
#elif __BYTE_ORDER == __BIG_ENDIAN
15
# define STORE32N(buffer,offset,value)   { printf("Big Endian\n"); store32(buffer, offset, value); }
16
#else
17
# error __BYTE_ORDER not defined
18
#endif

von olpo (Gast)


Lesenswert?

hab nochmal einen manuellen Test gemacht, es ist also doch alles 
little-endian.

von olpo (Gast)


Lesenswert?

ok, anscheinend hat hat ARM Schwierigkeiten mit unaligned memory. Intel 
buegelt das angeblich aus.
1
unsigned char *dest;
2
unsigned long src;
3
// ...
4
5
memcpy(&dest, &src, 4);

Das Problem ist wohl, dass "dest" vom Typ char ist und somit kleiner als 
die zu kopierenden 4 Byte, oder?
Oder kopiere ich an die Adresse vom Pointer *dest?

Egal,
das ganze ist Legacy Code, den ich jetzt auf ARM laufen lassen will.
Wie behebe ich das Problem am saubersten, ohne viel in den Code 
einzugreifen.

von Daniel A. (daniel-a)


Lesenswert?

olpo schrieb:
> ok, anscheinend hat hat ARM Schwierigkeiten mit unaligned memory.
1
unsigned char *dest;
2
unsigned long src;
3
memcpy(&dest, &src, 4);
> Das Problem ist wohl, dass "dest" vom Typ char ist.
Nein, dest ist ein pointer auf char daten. wenn du den poiner dest 
referenzierst, hast du einen pointer auf einen pointer auf char daten.
Der wert des Pointers (dessen adresse), welche du überschreibst, wobei 
du annimst, aber nicht prüfst, ob diese grösser oder gleich 4 ist, ist 
garantiert aligned.

von (prx) A. K. (prx)


Lesenswert?

olpo schrieb:
> ok, anscheinend hat hat ARM Schwierigkeiten mit unaligned memory.

Nicht generell. Manche können es, manche nicht.
Nur betrifft das den gezeigten Fall nicht.

: Bearbeitet durch User
von Norbert (Gast)


Lesenswert?

olpo schrieb:
> Hallo zusammen,
>
> ich habe ein Programm, das memcpy verwendet.
> Allerdings stuerzt das Programm ab, was, glaube ich, an "region overlap"
> bei der Funktion memcpy() liegt.
1
memcpy(80006e80, 80006e84, 4):

> Da ein "region overlap" bei memcpy() zu Problemen fuehren kann, soll man
> wohl eher memmove() verwenden.
> Ich habe ebenfalls gelesen, dass die meisten Prozessoren oder Compiler
> memcpy() wie memmove() behandeln, um solch ein Laufzeitfehler
> auszuschliessen.

Wahrscheinlich ist es ja nur ein Tipp/Übertragungsfehler, aber...

sind die beiden Werte
1
80006e80 und 80006e84
 nicht einfach nur float Zahlen und damit für ein memcpy völlig 
ungeeignet?
Sollte es da nicht heftige Warnungen des Compilers geben?

Oder sollte es eigentlich (eventuell mit einem Typecast):
1
memcpy(0x80006e80, 0x80006e84, 4):
 heissen?

Nur so ein Gedanke.

von olpo (Gast)


Lesenswert?

Norbert schrieb:
>
> Wahrscheinlich ist es ja nur ein Tipp/Übertragungsfehler, aber...
>
> sind die beiden Werte80006e80 und 80006e84 nicht einfach nur float
> Zahlen und damit für ein memcpy völlig
> ungeeignet?

Ja, das war nur faul geschrieben und auch mit den falschen Adressen.
Richtig ist es so:
1
memcpy(0x80004e8e, 0x80004e3c, 4);
2
// Allignment ERROR at memcpy 0x80004e8e

A. K. schrieb:
> olpo schrieb:
>> ok, anscheinend hat hat ARM Schwierigkeiten mit unaligned memory.
>
> Nicht generell. Manche können es, manche nicht.
> Nur betrifft das den gezeigten Fall nicht.

Also , hier passt alles?
Wie kann es dann zu einem Alignment Error kommen?
Hat jmd Vorschlaege, nach was ich gucken kann?
Genau an dieser memcpy()-Stelle fliegt er raus.

von (prx) A. K. (prx)


Lesenswert?

olpo schrieb:
> Wie kann es dann zu einem Alignment Error kommen?

Im memcpy selbst darf kein alignment error ausgelöst werden.

: Bearbeitet durch User
von olpo (Gast)


Lesenswert?

Ok, anscheinend laeuft man mit struct (und ARM) gerne in diese 
unalignment Falle.

Bei meinem Fall kommt tatsaechlich ein struct vor. Ich kann aber die 
problematische Stelle nicht ausmachen.
Versucht er das struct auf long zu "alignen"?
1
struct myBuf
2
{
3
 uint32_t size;
4
 uint32_t used;
5
 uint32_t flags;
6
 unsigned char buffer[MAX_BUFF_SIZE];
7
};
8
9
10
void foo( struct myBuf *buf)
11
{
12
 va_list argp;
13
 unsigned char *dest;
14
 unsigned long src;
15
16
 va_start(argp,buf);
17
 
18
 src = (unsigned long) va_arg(argp,unsigned long);
19
20
 memcpy(&dest, &src, 4);
21
}

von Klaus W. (mfgkw)


Lesenswert?

Häh?
Was hast du damit vor?

buf ist die Adresse einer struct (hoffentlich, je nachdem, wie du die 
Funktion aufrufst).

Diese Adresse kopierst du über va_arg (merkwürdigerweis als unsigned 
long betrachtet) in die lokale Variable src.
Abgesehen davon, daß die Typen natürlich passen (Adresse in einer 
unsigned long), enthält src jetzt die Adresse der struct des Aufrufers.

Dann übergibst du an memcpy die Adresse der lokalen Variable src. memcpy 
wird also ab der Adresse 4 Byte kopieren - es wird also die Adresse der 
struct kopiert.

Das wolltest so wahrscheinlich nicht haben?

von Markus F. (mfro)


Lesenswert?

Klaus Wachtler schrieb:
> Diese Adresse kopierst du über va_arg (merkwürdigerweis als unsigned
> long betrachtet) in die lokale Variable src.

Ähm, nö. Noch schlimmer.

Kopiert wird das auf buf folgende Argument (das möglicherweise da ist 
oder auch nicht).

Die Funktion sollte noch eine Ellipsis bekommen, um anzuzeigen, daß eine 
variable Argumentliste erwartet wird. Außerdem irgendeinen Parameter, 
der ihr sagt, wieviele Argumente grade zu erwarten sind.

So ist das jedenfalls nach Problemen gebettelt.

von Klaus W. (mfgkw)


Lesenswert?

Markus F. schrieb:
> Kopiert wird das auf buf folgende Argument (das möglicherweise da ist
> oder auch nicht).

Stimmt, hatte ich ganz übersehen.

Der zusätzliche Versatz macht es dann auch nicht mehr besser :-)

von olpo (Gast)


Lesenswert?

Ich raff den Code auch nicht, aber das ist Legacy Code von IBM(!).

Ich habe den Code nochmal um die Zuweisung an Destination erweitert. 
Vielleicht ergibt es so mehr sinn?
Was macht denn va_arg in dem Context?
1
struct myBuf
2
{
3
 uint32_t size;
4
 uint32_t used;
5
 uint32_t flags;
6
 unsigned char buffer[MAX_BUFF_SIZE];
7
};
8
9
10
void foo( struct myBuf *buf)
11
{
12
 va_list argp;
13
 unsigned char *dest;
14
 unsigned long src;
15
 unsigned char *buffer = buf->buffer;
16
17
 va_start(argp,buf);
18
 dest = &buffer[buf->used];
19
 
20
 src = (unsigned long) va_arg(argp,unsigned long);
21
22
 memcpy(&dest, &src, 4);
23
}

Aber ein Alignment Fault laesst sich hier nicht erkennen, oder wie?

von Markus F. (mfro)


Lesenswert?

olpo schrieb:
> Was macht denn va_arg in dem Context?

Kann man nur sagen, wenn Du auch den Aufruf der Funktion postest.

Wenn da nach buf noch ein Argument kommt, müsste man sich genau 
anschauen, was da gemacht wird.

Wenn nicht, könnte das möglicherweise ein Versuch sein, erstens den 
aufrufenden Stackframe (z.B. für eine Art "setjmp()") zu manipulieren 
und zweitens den eigenen Job bis in alle Ewigkeit zu erhalten (was ja 
offensichtlich nicht funktioniert hat, sonst wär' der, der das 
verbrochen hat, ja noch zu greifen).

von Klaus W. (mfgkw)


Lesenswert?

Wie bereits weiter oben steht: in memcpy kann es kein Problem mit 
alignment geben, weil diese Funktion auch mit ungeraden Adressen 
hantieren kann.

Aber du greifst gezielt neben alle irgendwie definierten Werte zu mit 
deinem verkorksten va_arg-Müll.
Wenn der Rest des Programms genaus schlecht ist, wie das was man hier 
sieht, würde ich auch nicht darauf wetten, daß &buffer[buf->used] 
kleiner gleich 4 Byte vor dem Ende des Puffers landet.
Da ist es sinnlos zu spekulieren, warum etwas schief geht.


Es könnte überschriebene Rücksprungadresse geben, verbogene Stackframes 
oder ziemlich alles andere geben.

Bestenfalls könnte man gezielter spkulieren, wenn man das ganze Programm 
sieht.
Ob sich das jemand antun will, wage ich aber zu bezweifeln.

von (prx) A. K. (prx)


Lesenswert?

stdarg.h Kram ohne ... in der Parameterliste zu verwenden fordert 
Probleme heraus. Falls der Code im Original exakt so aussieht: kopierter 
Mist bleibt Mist. Insbesondere wenn der Mist beispielsweise von x86 nach 
ARM kopiert worden sein sollte (andere Technik der Parameterübergabe).

: Bearbeitet durch User
von olpo (Gast)


Lesenswert?

Ach mist, ich habe eine Fehler oben in dem Beispiel-Code gemacht.
Es muss so aussehen:
1
unsigned char *buf;
2
unsigned long src;
3
4
memcpy(&buf[0], &src, 4);

Alignment Error?
buf ist also ein Array von Chars. Und so frisst das ARM nicht, weil Char 
!= 4Byte ist, oder?

von Daniel A. (daniel-a)


Lesenswert?

olpo schrieb:
> unsigned char *buf;
> unsigned long src;
>
> memcpy(&buf[0], &src, 4);

Da hier buf keinen definierten Wert hat, also ins nirvana zeigt, ist das 
schreiben nach buf unsinnig. Zeige doch mal den echten gesammten Code 
der Funktion, falls diese existiert, oder zumindest was diese tun soll.

von Markus F. (mfro)


Lesenswert?

olpo schrieb:
> Alignment Error?
> buf ist also ein Array von Chars. Und so frisst das ARM nicht, weil Char
> != 4Byte ist, oder?

Nein. memcpy() ist so definiert, daß es void-Zeiger akzeptiert und muß 
(weil die auf jeden beliebigen Datentyp zeigen können) unabhängig von 
der Plattform auch von/auf ungerade Adressen kopieren können.

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

olpo schrieb:
> memcpy(80006e80, 80006e84, 4):

olpo schrieb:
> memcpy(&dest, &src, 4);

Daniel A. schrieb:
> unsigned char *dest;
> unsigned long src;
> memcpy(&dest, &src, 4);

olpo schrieb:
> memcpy(0x80004e8e, 0x80004e3c, 4);
> // Allignment ERROR at memcpy 0x80004e8e

olpo schrieb:
> struct myBuf
> {
>  uint32_t size;
>  uint32_t used;
>  uint32_t flags;
>  unsigned char buffer[MAX_BUFF_SIZE];
> };
>
> void foo( struct myBuf *buf)
> {
>  va_list argp;
>  unsigned char *dest;
>  unsigned long src;
>
>  va_start(argp,buf);
>
>  src = (unsigned long) va_arg(argp,unsigned long);
>
>  memcpy(&dest, &src, 4);
> }

olpo schrieb:
> struct myBuf
> {
>  uint32_t size;
>  uint32_t used;
>  uint32_t flags;
>  unsigned char buffer[MAX_BUFF_SIZE];
> };
>
> void foo( struct myBuf *buf)
> {
>  va_list argp;
>  unsigned char *dest;
>  unsigned long src;
>  unsigned char *buffer = buf->buffer;
>
>  va_start(argp,buf);
>  dest = &buffer[buf->used];
>
>  src = (unsigned long) va_arg(argp,unsigned long);
>
>  memcpy(&dest, &src, 4);
> }

olpo schrieb:
> Ach mist, ich habe eine Fehler oben in dem Beispiel-Code gemacht.
> Es muss so aussehen:
> unsigned char *buf;
> unsigned long src;
>
> memcpy(&buf[0], &src, 4);

Wieviele Varianten kommen denn noch?

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.