Toon posts:

[C] Dynamic function call?

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hi,

Ik wil graag in c een function pointer aanroepen met een dynamic aantal args, hoe kan je dit het beste doen in c?

Ik heb het nu opgelost door in asm het te doen maar dat is toch niet 100% stable

  • _Squatt_
  • Registratie: Oktober 2000
  • Niet online
Je kunt toch een functie declareren met '...':
C:
1
void func_variable_args( int arg1, ...)

Dan moet je in de functie nog het een en ander doen met va_list geloof ik, maar dat is vast wel op internet te vinden. Ik dacht dat al die dingen in varargs.h worden gedefinieerd.

[ Voor 4% gewijzigd door _Squatt_ op 04-06-2003 19:50 ]

"He took a duck in the face at two hundred and fifty knots."


Verwijderd

Topicstarter
_Squatt_ schreef op 04 June 2003 @ 19:47:
Je kunt toch een functie declareren met '...':
C:
1
void func_variable_args( int arg1, ...)

Dan moet je in de functie nog het een en ander doen met va_list geloof ik, maar dat is vast wel op internet te vinden. Ik dacht dat al die dingen in varargs.h worden gedefinieerd.
idd, dat klopt maar ik wil pricies het andere:

ik wil een function dynamic aanroepen, zoiets als dit:

callFunction(unsigned int funcPointer, unsigned int *argPointers);

in ieder geval dat je dynamic aantal args kan door geven aan een function

Verwijderd

Topicstarter
even nog voor de duidelijkheid hier mn function (wel uit mn hoofd dus het kan fout zijn maar het gaat me voor de grote lijnen):


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
unsigned int callFuncPointer(unsigned int funcPointer, unsigned short argCount, unsigned int *argPointers) {

    unsigned short i = 0;
    unsigned int argPointer = 0;
    unsigned int returnValuePointer = 0;

    i = argCount;

    asm {

        loopCreatePushes:
    }

    argPointer = argPointers[i];

    asm {
        push    argPointer
        add i, -1h
        cmp i, oh
        jne loopCreatePushes
        call    funcPointer
        loopCreatePops:
        pop eax
        add i, 1h
        cmp i, argCount
        jne loopCreatePops
        mov returnValuePointer, eax
    }

    return returnValuePointer;
}

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Ik weet niet of er een mooiere manier is om te doen wat je wilt, maar hier is een werkende asm versie. Het is VC code, je moet het zelf maar even omschrijven naar je fav compiler, zorg iig dat ie geen stackframe gaat opzetten want de asm code gaat er vanuit dat dat niet gebeurt (declspec(naked)):
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
unsigned int __declspec(naked) 
callFuncPointer(void *pFunc,
                unsigned int num,
                unsigned int *pArgs) 
{
    _asm
    {
        push    ebx
        mov     ecx, [esp+0Ch] ; numArgs
        mov     eax, [esp+08h] ; pFunc
        mov     edx, [esp+10h] ; pArgs
        test    ecx, ecx
        mov     ebx, ecx
        jz      _callFunc
    _pushParams:
        push    dword ptr [edx+ecx*4-4]
        dec     ecx
        jnz     _pushparams
    _callFunc:
        call    eax
        shl     ebx, 2
        add     esp, ebx
        pop     ebx
        ret
    }
}

void main()
{
    unsigned int *p = new unsigned int[4];
    p[0] = reinterpret_cast<unsigned int>("Values are: %d, %d and %d\n");
    p[1] = 1;
    p[2] = 2;
    p[3] = 3;
    callFuncPointer(printf, 4, p);
    delete[] p;
}

[ Voor 4% gewijzigd door madwizard op 04-06-2003 21:09 ]

www.madwizard.org


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Declareer de functie als een functie met een argument, een linked list van void* pointers, of pass een array en lengte.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Verwijderd

Topicstarter
madwizard schreef op 04 June 2003 @ 21:06:
Ik weet niet of er een mooiere manier is om te doen wat je wilt, maar hier is een werkende asm versie. Het is VC code, je moet het zelf maar even omschrijven naar je fav compiler, zorg iig dat ie geen stackframe gaat opzetten want de asm code gaat er vanuit dat dat niet gebeurt (declspec(naked)):
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
unsigned int __declspec(naked) 
callFuncPointer(void *pFunc,
                unsigned int num,
                unsigned int *pArgs) 
{
    _asm
    {
        push    ebx
        mov     ecx, [esp+0Ch] ; numArgs
        mov     eax, [esp+08h] ; pFunc
        mov     edx, [esp+10h] ; pArgs
        test    ecx, ecx
        mov     ebx, ecx
        jz      _callFunc
    _pushParams:
        push    dword ptr [edx+ecx*4-4]
        dec     ecx
        jnz     _pushparams
    _callFunc:
        call    eax
        shl     ebx, 2
        add     esp, ebx
        pop     ebx
        ret
    }
}

void main()
{
    unsigned int *p = new unsigned int[4];
    p[0] = reinterpret_cast<unsigned int>("Values are: %d, %d and %d\n");
    p[1] = 1;
    p[2] = 2;
    p[3] = 3;
    callFuncPointer(printf, 4, p);
    delete[] p;
}
Hi,

ziet er leuk uit maar mn stukje asm heb ik gemaakt uit een boek/output van een c compiler

kan je mischien wat meer info geven over wat je doe?

want ik dacht dat je de pointers alle maal moet pushen voordat je de function aan roep (call funcPointer) + volgens mij haal je geen return pointer van de function die je aanroep op

  • madwizard
  • Registratie: Juli 2002
  • Laatst online: 26-10-2024

madwizard

Missionary to the word of ska

Je moet alle pointers (/argumenten, wat het ook zijn) ook pushen, alleen bij de C calling convention moet je dat in omgekeerde volgorde doen. De return waarde van de functie (als dat is wat je bedoelt met return pointer) geef ik wel terug, de conventie is namelijk dat voor een int (of het meeste wat even groot is als een int) teruggegeven wordt in eax.
code:
1
        push    ebx

Bewaart ebx op de stack, omdat ebx/esi/edi/ebp onveranderd moeten zijn na het uitvoeren van een functie.
code:
1
2
3
        mov     ecx, [esp+0Ch] ; numArgs 
        mov     eax, [esp+08h] ; pFunc 
        mov     edx, [esp+10h] ; pArgs

Haalt de drie argumenten van de functie op en stopt ze in ecx (numArgs), eax (pFunc) en edx (pArgs).

code:
1
2
3
        test    ecx, ecx 
        mov     ebx, ecx 
        jz      _callFunc

Kijkt of ecx 0 is (geen parameters), kopieert ecx naar ebx omdat die later nodig is en ebx niet door aan te roepen functie gewijzigd wordt maar ecx wel. Bovendien wordt ecx ook nog gewijzigd in de loop. Als ecx 0 was wordt het pushen van de parameters overgeslagen en direct de functie aangeroepen (jump naar _callFunc), anders valt ie er doorheen en gaat ie de parameters pushen:
code:
1
2
3
4
    _pushParams: 
        push    dword ptr [edx+ecx*4-4] 
        dec     ecx 
        jnz     _pushparams

edx is een pointer naar de parameter lijst. ecx is in het begin het aantal parameters. Nu moeten de parameters in omgekeerde volgorde gepusht worden, dus bijvoorbeeld bij 4 parameters eerst index 3, dan 2, dan 1 en dan 0.
De array begint bij edx, vanaf dan neemt elke index 4 bytes in (int). Element x staat dus op edx + 4 * x. In dit geval kan je dan dus edx + 4 * ecx gebruiken, alleen moet er nog een - 4 bij omdat ecx in het begin 1 meer dan de hoogste index is (aantal elementen -1 = hoogste index).
Dan wordt in elke iterator ecx met 1 verminderd en teruggesprongen als die nog niet 0 is (=nog niet klaar). Bovenstaande komt dus overeen met:
C:
1
2
3
4
5
6
7
int ecx = aantal parameters;
int *edx = pointer naar array;
while(ecx>0)
{
    push(edx[ecx-1]);
    ecx--;
}


Dan:
code:
1
2
    _callFunc: 
        call    eax

De functie pointer zat in eax, dus call eax voert gewoon de functie uit.

code:
1
2
        shl     ebx, 2 
        add     esp, ebx

De C calling convention zegt dat de caller de stack moet opruimen. In dit geval is dat aan ruimte aantal parameters * 4. Ebx was het aantal parameters, 'shl ebx, 2' is ebx<<2 oftewel ebx*4. 'Add esp, ebx' zorgt dat de stack pointer opgehoogd wordt met de juiste waarde zodat deze weer correct is.
code:
1
2
        pop     ebx 
        ret

Geef ebx z'n orginele waarde terug en return naar de caller. Na de 'call eax' is de return waarde van die functie in eax gezet. Eax is daarna niet meer aangepast en wordt door de caller dus gezien als de return waarde van deze functie.

[ Voor 4% gewijzigd door madwizard op 04-06-2003 22:34 ]

www.madwizard.org


Verwijderd

Topicstarter
1000 maal tnx

ik ga het morgen gelijk uit proberen

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Waarom wil je dat eigenlijk doen?
Is er geen andere (nettere) manier?

Verwijderd

Topicstarter
OlafvdSpek schreef op 04 juni 2003 @ 22:54:
Waarom wil je dat eigenlijk doen?
Is er geen andere (nettere) manier?
ik maak een php extension waardoor ik van uit php public symbols op netware kan aanroepen

en volgens mij is dit de enige manier (door midel van asm)

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Ik heb geen ervaring met PHP extensions, maar heb je dit nodig voor de interface met PHP of met NW?
Pagina: 1