¿Como es posible retornar estructuras con la convencion de llamadas cdecl?

Iniciado por Usuario887, 6 Marzo 2021, 22:46 PM

0 Miembros y 1 Visitante están viendo este tema.

Usuario887

Tengo una pequeña duda...

En C es posible hacer esto:

/*...*/
struct _hdr
char data1;
double data2;
char *data3;
};

/*...*/

struct _hdr foo (void)
{
    struct _hdr instance;
    /*...*/
    return instance;
}
/*...*/


¿Como es posible hacerlo segun la convencion de llamadas de C?

CitarInteger values and memory addresses are returned in the EAX register
https://en.wikipedia.org/wiki/X86_calling_conventions

Entiendo que una estructura no es un valor entero (a menos que sea una direccion de memoria). Entonces, ¿Como haciendo uso de cdecl se puede retornar una estructura entera? La citada en el codigo no cabe siquiera en EDX:EAX.

Saludos y gracias por su atencion.

Eternal Idol

Es a gusto del compilador.

CitarIn regard to how to return values, some compilers return simple data structures with a length of 2 registers or less in the register pair EAX:EDX, and larger structures and class objects requiring special treatment by the exception handler (e.g., a defined constructor, destructor, or assignment) are returned in memory. To pass "in memory", the caller allocates memory and passes a pointer to it as a hidden first parameter; the callee populates the memory and returns the pointer, popping the hidden pointer when returning

https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl

struct _hdr foo (void)
   {
       struct _hdr instance;
instance.data1 = 'A';
instance.data2 = 45.04;
instance.data3 = "PROBANDO 123";
       return instance;
   }


void main()
{
foo();
__debugbreak();
}


Código (asm) [Seleccionar]
0:000> u main
test!main [c:\src\test.c @ 26]:
00ffaa50 55              push    ebp
00ffaa51 8bec            mov     ebp,esp
00ffaa53 83ec18          sub     esp,18h
00ffaa56 8d45e8          lea     eax,[ebp-18h]
00ffaa59 50              push    eax
00ffaa5a e80e80ffff      call    test!ILT+6760(_foo) (00ff2a6d)
00ffaa5f 83c404          add     esp,4
00ffaa62 cc              int     3
00ffaa63 33c0            xor     eax,eax
00ffaa65 8be5            mov     esp,ebp
00ffaa67 5d              pop     ebp
00ffaa68 c3              ret


Al frenarse en el breakpoint:
0:000> dt test!_Hdr @eax
  +0x000 data1            : 65 'A'
  +0x008 data2            : 45.039999999999999147
  +0x010 data3            : 0x00cc3290  "PROBANDO 123"

Código (asm) [Seleccionar]
0:000> u test!foo
test!foo [c:\src\test.c @ 15]:
00ffaa00 55              push    ebp
00ffaa01 8bec            mov     ebp,esp
00ffaa03 83ec18          sub     esp,18h
00ffaa06 c645e841        mov     byte ptr [ebp-18h],41h ;'A'
00ffaa0a f20f1005a88e0401 movsd   xmm0,mmword ptr [test!_real (01048ea8)] ;ver abajo
00ffaa12 f20f1145f0      movsd   mmword ptr [ebp-10h],xmm0
00ffaa17 c745f890320501  mov     dword ptr [ebp-8],offset test!__acrt_initial_multibyte_data+0x220 (01053290) ;ver abajo
00ffaa1e 8b4508          mov     eax,dword ptr [ebp+8]
00ffaa21 8b4de8          mov     ecx,dword ptr [ebp-18h]
00ffaa24 8908            mov     dword ptr [eax],ecx
00ffaa26 8b55ec          mov     edx,dword ptr [ebp-14h]
00ffaa29 895004          mov     dword ptr [eax+4],edx
00ffaa2c 8b4df0          mov     ecx,dword ptr [ebp-10h]
00ffaa2f 894808          mov     dword ptr [eax+8],ecx
00ffaa32 8b55f4          mov     edx,dword ptr [ebp-0Ch]
00ffaa35 89500c          mov     dword ptr [eax+0Ch],edx
00ffaa38 8b4df8          mov     ecx,dword ptr [ebp-8]
00ffaa3b 894810          mov     dword ptr [eax+10h],ecx
00ffaa3e 8b55fc          mov     edx,dword ptr [ebp-4]
00ffaa41 895014          mov     dword ptr [eax+14h],edx
00ffaa44 8b4508          mov     eax,dword ptr [ebp+8]
00ffaa47 8be5            mov     esp,ebp
00ffaa49 5d              pop     ebp
00ffaa4a c3              ret


0:000> dD 01048ea8 l1
01048ea8                   45.04
0:000> da 01053290
01053290  "PROBANDO 123"

Ahora podes probar sacando data2 de la estructura, data1 sera devuelto en EAX y data3 en EDX.
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

Usuario887

Supuse que se trataba de algo asi. No entiendo el codigo que usa el set de instrucciones MMX, pero entiendo lo que esta haciendo.

Aunque sinceramente pense que hacia uso de un ciclo para guardar los datos byte a byte.

CitarAhora podes probar sacando data2 de la estructura, data1 sera devuelto en EAX y data3 en EDX.

Me parece impresionante lo exhaustiva que llega a ser la tecnologia.

Saludos y gracias por tu respuesta.

Eternal Idol

Cita de: marax en  7 Marzo 2021, 12:54 PMAunque sinceramente pense que hacia uso de un ciclo para guardar los datos byte a byte.

A la larga lo terminara haciendo si la estructura es suficientemente extensa.

De nadas  ::)
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

BloodSharp

A ver que pasa con GCC:

Código (cpp) [Seleccionar]
#include <stdio.h>

struct _hdr
{
   char data1;
   double data2;
   char* data3;
};

struct _hdr __attribute__((__cdecl__)) foo()
{
   struct _hdr instance;
instance.data1 = 'A';
instance.data2 = 45.04;
instance.data3 = (char*)"PROBANDO 123";
   return instance;
}

int __attribute__((noinline)) __attribute__((__cdecl__)) foo2(int a, int b)
{
   return 0;
}

int main(int argc,char*argv[])
{
   struct _hdr estructura;
   int entero=foo2(1,2);
   estructura=foo();
   printf("%c %.2f %s %i\n",estructura.data1,estructura.data2,estructura.data3,entero);
   return 0;
}


Al parecer una función común y corriente como foo2 en cdecl funciona perfectamente, pero es interesante ver lo que pasa con foo:



Está pasando un puntero como argumento, lo interesante es que al parecer GCC cambia la convención a tipo stdcall:



Si arreglo y paso como parametro el puntero a la estructura vemos como el descompilador funciona casi retornando el mismo código original:



Por lo que en este caso aunque además de retornar la dirección del puntero (aunque no es usado) a la estructura también trabaja con un argumento oculto.


B#