Variale Anzahl Werte auf Stack schreiben

Gast #1702156
Lesenswert?

Hi,

wie kann ich unter C eine variable Anzahl an Werten auf den Stack legen?

Ich habe ein Programms und binaris (Quellcode nur teilweise), dass 
bisher Hex-Werte als Steuerzeichen erhält. Dieser Quellcode soll orginal 
bleiben.
Ich muss eine Art Kommandointerpreter hinzufügen, der Befehle von einem 
Terminal erhält, diese auf den Stack schiebt und dann die Funktionen so 
aufruft, wie die Hex-Routine tut. Die Hex-routine selbst muss dabei 
erhalten bleiben. Je nach Schnittstelle (CAN oder RS232) wird entweder 
die Hex-Funktion verwendet, oder der Interpreter.
Ich habe mir verschiede Parser und Interpreter aus der Codesammlung 
angeschaut. Da sind die Funktionen so vorbereitet, dass die ihre Werte 
aus einen array aus unions lesen. Das kann ich nicht machen. Ich muss 
zur Laufzeit ermitteln, was ich wie auf den Stack schiebe und dann eine 
Funktion aufrufen.

Dazu muss ich je nach Befehl immer andere Daten auf den Stack schreiben, 
nur wie mach ich das in C? Ich kenne stdarg um eine variale Anzahl an 
Parametern vom Stack zu holen, wie heißen die Umkehrfunktionen dafür?

Emax
#1702209
Lesenswert?

Was ich mir hier als Schweinerei vorstellen könnte:

Man könnte sich die zu übergebenden Bereiche in einem
anderen Puffer zusammenbauen und den als eine Folge von z.B int
interpretieren.
Dann ruft man eine passende aus einem Satz von Funktionen auf,
die dann die nötige Anzahl Werte aus dem Puffer nimmt und als
Parameter an deine Endfunktion liefert.

Also etwa so:
1
#include <stdlib.h>
2
#include <stddef.h>
3
#include <stdio.h>
4
//#include <string.h>
5
#include <stdint.h>
6
#include <stdarg.h>
7

8
void malmehrmalweniger( int anzahl, ... )
9
{
10
  int    i;
11

12
  va_list    val;
13
  va_start( val, anzahl );
14

15

16
  for( i=0; i<anzahl; ++i )
17
  {
18
    int   aktueller_wert = va_arg( val, int );
19
    printf( "%d 0x%08x\n", i, aktueller_wert );
20
  }
21
  va_end( val );
22
}
23

24
void ruf_malmehrmalweniger_auf_1( int wert1 )
25
{
26
  malmehrmalweniger( 1, wert1 );
27
}
28

29
void ruf_malmehrmalweniger_auf_2( int wert1, int wert2 )
30
{
31
  malmehrmalweniger( 2, wert1, wert2 );
32
}
33

34
void ruf_malmehrmalweniger_auf_3( int wert1, int wert2, int wert3 )
35
{
36
  malmehrmalweniger( 3, wert1, wert2, wert3 );
37
}
38

39
void ruf_malmehrmalweniger_auf_4( int wert1, int wert2, int wert3, int wert4 )
40
{
41
  malmehrmalweniger( 4, wert1, wert2, wert3, wert4 );
42
}
43

44
void ruf_malmehrmalweniger_auf( void *p, size_t n_bytes )
45
{
46
  switch( n_bytes )
47
  {
48
    case 1:
49
    case 2:
50
    case 3:
51
    case 4:
52
      ruf_malmehrmalweniger_auf_1( ((int*)p)[0] );
53
      break;
54

55
    case 5:
56
    case 6:
57
    case 7:
58
    case 8:
59
      ruf_malmehrmalweniger_auf_2( ((int*)p)[0], ((int*)p)[1] );
60
      break;
61

62
    case 9:
63
    case 10:
64
    case 11:
65
    case 12:
66
      ruf_malmehrmalweniger_auf_3( ((int*)p)[0], ((int*)p)[1], ((int*)p)[2] );
67
      break;
68

69
    case 13:
70
    case 14:
71
    case 15:
72
    case 16:
73
      ruf_malmehrmalweniger_auf_4( ((int*)p)[0], ((int*)p)[1], ((int*)p)[2], ((int*)p)[3] );
74
      break;
75

76
    default :
77

78
      break;
79
  }
80
}
81

82
int main( int nargs, char **args )
83
{
84
  // ausreichender Puffer für maximalen Stack:
85
  union
86
  {
87
    uint8_t     byte[0];
88
    int         i[4];
89
  } puffer;
90

91

92
  // Beispiel 1:
93
  // 3 Bytes zusammenbasteln
94
  printf( "Beispiel 1: 3 Bytes\n" );
95
  puffer.byte[0] = 0x12;
96
  puffer.byte[1] = 0x34;
97
  puffer.byte[2] = 0x56;
98
  ruf_malmehrmalweniger_auf( &puffer, 3 );
99

100
  // Beispiel 2:
101
  // 3 Bytes zusammenbasteln
102
  printf( "Beispiel 2: 8 Bytes\n" );
103
  puffer.byte[0] = 0x12;
104
  puffer.byte[1] = 0x34;
105
  puffer.byte[2] = 0x56;
106
  puffer.byte[3] = 0x78;
107
  puffer.byte[4] = 0x9a;
108
  puffer.byte[5] = 0xbc;
109
  puffer.byte[6] = 0xde;
110
  puffer.byte[7] = 0xf0;
111
  ruf_malmehrmalweniger_auf( &puffer, 8 );
112

113
  return 0;
114
}
malmehrmalweniger() soll deine Funktion sein, die du letztlich
aufrufen willst.

Ausgabe unter Linux:
1
klaus@vdr1:~ > gcc -Wall  -std=gnu99 t.c &&  ./a.out
2
Beispiel 1: 3 Bytes
3
0 0x08563412
4
Beispiel 2: 8 Bytes
5
0 0x78563412
6
1 0xf0debc9a

Voraussetzungen in diesem Beispiel:
- int werden auf dem aktuellen System direkt hintereinander übergeben
- die aufgerufene Funktion bekommt als erstes eine int, in der
  drin steht, wie viel Werte kommen (irgendwie muß sie ja
  erkennen, was da kommt)
- maximal 4 int in dieser Form
- man muß zusehen, daß die Felder reichen
#1702654
Lesenswert?

Was auch eventuell geht:
Dazu muss aber der Argumentpassing Mechanismus vom C Compiler und das 
was die Assemblerfunktion auf dem Stack haben möchte, absolut kompatibel 
sein. Ist das nicht der Fall, kannst du das gleich alles wieder 
vergessen.

Schweinereien mit einem Funktionspointer.
Du definierst dir einen Haufen typedefs, die alle möglichen 
Aufrufargumentlisten abdecken.
Dann holst du dir die Adresse der Assemblerfunktion, castest den Pointer 
mit dem richtigen typedef zurecht und rufst die Funktion auf.

Im Prinzip ähnlich zu dem, was Klaus weiter oben gezeigt hat.

Aber ich fürchte das Problem wird einfach sein, dass die Assembler 
Funktion einen völlig anderen Argument Passing Mechanismus benutzt, als 
dein C Compiler. Ich schätze ohne eine Assembler Zwischenschicht wird 
das nichts werden.
Gast #1702869
Lesenswert?

Hallo, ich danke euch sehr für die Antworten, Anregungen und Beispiele!
Ich werde es nach dem Vorschlag von  Klaus Wachtler realisieren, 
reserviere also eine Anzahl an char auf dem Stack und caste die dann 
irgendwie da drauf.

Gruß Emax

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