On 7 May 2012 08:41, Luc Fabresse <[email protected]> wrote: > Thank you Igor for the new version of NB. > I tested it and it works when returning structs. >
!! perfect !! :) > #Luc > > > > 2012/5/4 Igor Stasenko <[email protected]> >> >> On 4 May 2012 20:27, Nicolas Cellier <[email protected]> >> wrote: >> > I found this link quite detailed on the subject, but restricted to C++ >> > (not entirely sure C compiler produces exactly the same...) >> > >> > http://www.shell-storm.org/papers/files/657.pdf >> > >> thanks for the link, nicolas.. the information about these conventions >> are really sparse. >> >> > See table 7 for the case of returning objects... >> > >> > See also stack cleanup by, 32 bit gcc use hybrid method for structure >> > passed by values thru a pointer... >> > >> > Nicolas >> > >> > 2012/5/4 Igor Stasenko <[email protected]>: >> >> On 4 May 2012 19:18, Nicolas Cellier >> >> <[email protected]> wrote: >> >>> Yes, on max too >> >>> >> >>> https://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html >> >>> >> >>> Structures. The called function returns structures according to their >> >>> aligned size. >> >>> >> >>> Structures 1 or 2 bytes in size are placed in EAX. >> >>> >> >>> Structures 4 or 8 bytes in size are placed in: EAX and EDX. >> >>> >> >> >> >> okay.. i fixed it in NativeBoost-Core-IgorStasenko.58 >> >> >> >>> Structures of other sizes are placed at the address supplied by >> >>> the caller. For example, the C++ language occasionally forces the >> >>> compiler to return a value in memory when it would normally be >> >>> returned in registers. See “Passing Arguments” for more information. >> >>> >> >>> I wonder if a structure of size 3 bytes can exist or is automatically >> >>> extended on 4 bytes... >> >>> >> >> yes.. struct alignment is what i fear of.. >> >> IMO it is actually silly to not return struct in registers if it less >> >> than 8 bytes >> >> but not power of 2.. >> >> >> >> sounds like an artefact of establishing the standards :) >> >> >> >>> $ cat > test_call.c <<END >> >>> >> >>> #include <stdio.h> >> >>> typedef struct { char a,b,c; } abc; >> >>> int main() { >> >>> abc x; >> >>> printf("sizeof(abc)=%d\n",sizeof x); >> >>> return 0; >> >>> } >> >>> END >> >>> >> >>> $ gcc test_call.c >> >>> $ ./a.exe >> >>> sizeof(abc)=3 >> >>> >> >>> And what would be the calling conventions of cygwin gcc ? >> >>> >> >>> $ cat > test_call.c <<END >> >>> >> >>> #include <stdio.h> >> >>> typedef struct { char a,b,c; } abc; >> >>> abc sub() { >> >>> abc result; >> >>> result.a='a'; >> >>> result.b='b'; >> >>> result.c='c'; >> >>> return result; >> >>> } >> >>> int main() { >> >>> abc x=sub(); >> >>> printf("sizeof(abc)=%d abc.a=$c\n",sizeof x,x.a); >> >>> return 0; >> >>> } >> >>> END >> >>> >> >>> $ gcc test_call.c >> >>> $ ./a.exe >> >>> sizeof(abc)=3 abc.a=a >> >>> >> >>> $ gcc -S test_call.c >> >>> $ cat test_call.S >> >>> >> >>> .file "test_call.c" >> >>> .text >> >>> .globl _sub >> >>> .def _sub; .scl 2; .type 32; .endef >> >>> _sub: >> >>> pushl %ebp >> >>> movl %esp, %ebp >> >>> subl $16, %esp >> >>> movl 8(%ebp), %eax >> >>> movb $97, -3(%ebp) >> >>> movb $98, -2(%ebp) >> >>> movb $99, -1(%ebp) >> >>> movzwl -3(%ebp), %edx >> >>> movw %dx, (%eax) >> >>> movzbl -1(%ebp), %edx >> >>> movb %dl, 2(%eax) >> >>> leave >> >>> ret $4 >> >>> .def ___main; .scl 2; .type 32; .endef >> >>> .section .rdata,"dr" >> >>> LC0: >> >>> .ascii "sizeof(abc)=%d\12\0" >> >>> .text >> >>> .globl _main >> >>> .def _main; .scl 2; .type 32; .endef >> >>> _main: >> >>> leal 4(%esp), %ecx >> >>> andl $-16, %esp >> >>> pushl -4(%ecx) >> >>> pushl %ebp >> >>> movl %esp, %ebp >> >>> pushl %ecx >> >>> subl $36, %esp >> >>> call ___main >> >>> leal -11(%ebp), %eax >> >>> movl %eax, (%esp) >> >>> call _sub >> >>> subl $4, %esp >> >>> movl $3, 4(%esp) >> >>> movl $LC0, (%esp) >> >>> call _printf >> >>> movl $0, %eax >> >>> movl -4(%ebp), %ecx >> >>> leave >> >>> leal -4(%ecx), %esp >> >>> ret >> >>> .def _printf; .scl 2; .type 32; .endef >> >>> >> >>> But of course, you already were faster than me... >> >>> >> >>> Nicolas >> >>> >> >>> 2012/5/4 Igor Stasenko <[email protected]>: >> >>>> On 4 May 2012 18:37, Eliot Miranda <[email protected]> wrote: >> >>>>> >> >>>>> >> >>>>> On Fri, May 4, 2012 at 6:13 AM, Igor Stasenko <[email protected]> >> >>>>> wrote: >> >>>>>> >> >>>>>> On 4 May 2012 10:38, Luc Fabresse <[email protected]> wrote: >> >>>>>> > Hi Igor, >> >>>>>> > >> >>>>>> >> >> >>>>>> >> there is a workaround. >> >>>>>> >> all structs in C is returned via pointer. >> >>>>>> >> so, actually a true return type of a function is CvSize* >> >>>>>> > >> >>>>>> > >> >>>>>> > I agree that usually structs are returned through pointers. >> >>>>>> > But here it is not the case. >> >>>>>> > >> >>>>>> > I want to wrap this function: >> >>>>>> > CvSize cvGetSize( const CvArr* arr ); >> >>>>>> > >> >>>>>> > and the CvSize struct is returned by value. Am I wrong? >> >>>>>> > >> >>>>>> >> >>>>>> i don't know.. this is a bit shady part of C ABI. >> >>>>>> Some compilers use return-by-value, some return by pointer >> >>>>>> by forcing a caller to pass a hidden implicit argument as a pointer >> >>>>>> to >> >>>>>> the struct, which then filled with values by >> >>>>>> the function you call. >> >>>>> >> >>>>> >> >>>>> IIRC x86 ABIs (all the ones I encountered at least, windows, mac, >> >>>>> linux, >> >>>>> solaris) support structure return (by-value structure return) by >> >>>>> passing a >> >>>>> hidden first argument which is a pointer to a structure into which >> >>>>> to copy >> >>>>> the result. The callee copies the result back through this pointer. >> >>>>> >> >>>>> Where these ABIs differ is in returning small structures. On win32 >> >>>>> structures a power-of-two in size of 8 bytes or less are returned in >> >>>>> EAX:EDX. IIRC on linux and mac all structures are returned through >> >>>>> the >> >>>>> hidden first argument pointer. See >> >>>>> ThreadedIA32FFIPlugin>>returnStructInRegisters: >> >>>>> >> >>>> on macs (at least what gcc generates) it also returns structs <=8 >> >>>> bytes size in registers: >> >>>> >> >>>> >> >>>> so , currently i implemented it like that: >> >>>> if sizeof(struct) <= 8 then i assume function returns it in EAX: EDX >> >>>> otherwise via hidden pointer. >> >>>> >> >>>>>> >> >>>>>> >> >>>>>> It is easy to add support for that, but to make it work correctly >> >>>>>> can >> >>>>>> be tricky. >> >>>>>> See this, for example: >> >>>>>> >> >>>>>> >> >>>>>> http://stackoverflow.com/questions/161788/are-there-any-downsides-to-passing-structs-by-value-in-c-rather-than-passing-a >> >>>>>> >> >>>>>> >> >>>>>> >> >> >>>>>> >> >> >>>>>> >> so, what you do is to change the return value to simple void* >> >>>>>> >> and then copy the contents of struct into instance of >> >>>>>> >> corresponding >> >>>>>> >> NBExternalStructure subclass >> >>>>>> >> using #fromPointer: method.. to conveniently access its fields >> >>>>>> >> values. >> >>>>>> > >> >>>>>> > >> >>>>>> > yes I saw that in NB tests. >> >>>>>> > >> >>>>>> >> >> >>>>>> >> >> >>>>>> >> >> >>>>>> >> but this is in general, in your case this function is actually >> >>>>>> >> inlined >> >>>>>> >> by compiler (as CV_INLINE suggests), so there could be even no >> >>>>>> >> exported symbol for it in dynamic library. >> >>>>>> >> and the function is actually so simple, that you don't need to >> >>>>>> >> wrap it >> >>>>>> >> at >> >>>>>> >> all. >> >>>>>> >> you can just create a subclass of NBExternalStructure , named >> >>>>>> >> CvSize, >> >>>>>> >> implement fieldDesc method as: >> >>>>>> >> >> >>>>>> >> fieldsDesc >> >>>>>> >> ^ #( >> >>>>>> >> int width; >> >>>>>> >> int height >> >>>>>> >> ) >> >>>>>> >> >> >>>>>> >> >> >>>>>> >> and if you invoke: >> >>>>>> >> >> >>>>>> >> CvSize new width: 1 height:2 >> >>>>>> >> >> >>>>>> >> it will be equivalent as if you will call cvSize(1,2) function. >> >>>>>> > >> >>>>>> > >> >>>>>> > yes it is exactly what I did. >> >>>>>> > >> >>>>>> > So my problem is: >> >>>>>> > >> >>>>>> > NBCvSize implemented as a subclass of NBExternalStruct with >> >>>>>> > fieldDesc >> >>>>>> > correctly set up. >> >>>>>> > Then wrap the function cvGetSize: >> >>>>>> > >> >>>>>> > getSize >> >>>>>> > self nbCall: #(NBCvSize cvGetSize(IplImage self)) module: >> >>>>>> > LIB_CV. >> >>>>>> > >> >>>>>> > But I get a debugger because: >> >>>>>> > >> >>>>>> > NBExternalStruct>>coerceReturn: gen >> >>>>>> > " ... should we support handling return of external structures? " >> >>>>>> > self error: 'returning pointer to structure?' >> >>>>>> > >> >>>>>> > And I have no idea how to implement this (black magic EAX pop >> >>>>>> > push ;-)) >> >>>>>> > to >> >>>>>> > coerce result of struct. >> >>>>>> > >> >>>>>> >> >>>>>> >> >>>>>> you don't. if function takes an implicit struct pointer, you can >> >>>>>> just >> >>>>>> rewrite the function signature from >> >>>>>> NBCvSize cvGetSize(IplImage self) >> >>>>>> to: >> >>>>>> >> >>>>>> void cvGetSize(NBCvSize hidden, IplImage self) >> >>>>>> >> >>>>>> and so, you pass a fresh instance of NBCvSize as argument, which >> >>>>>> function then fill. >> >>>>>> But if C compiler using registers to return struct.. then you're >> >>>>>> screwed >> >>>>>> :) >> >>>>>> >> >>>>>> Anyways, Luc i will try to read docs about C ABI and see if we can >> >>>>>> easily add support for that. >> >>>>>> >> >>>>>> -- >> >>>>>> Best regards, >> >>>>>> Igor Stasenko. >> >>>>>> >> >>>>> >> >>>>> >> >>>>> >> >>>>> -- >> >>>>> best, >> >>>>> Eliot >> >>>>> >> >>>> >> >>>> >> >>>> >> >>>> -- >> >>>> Best regards, >> >>>> Igor Stasenko. >> >>> >> >> >> >> >> >> >> >> -- >> >> Best regards, >> >> Igor Stasenko. >> >> >> > >> >> >> >> -- >> Best regards, >> Igor Stasenko. >> > -- Best regards, Igor Stasenko.
