C++ calling convention (thiscall) and assembly

Started by
7 comments, last by Staffan 22 years, 10 months ago
I'm trying to implement my class, or more accuratley some methods of my class, with assembly code, no inline assembly but pure asm code. My problem is that I don't find any information on the thiscall calling convention...Yes, I read the entire NASM docs. I think I remember the this pointer is passed in ecx? How are the arguments sent (which order are they pushed)? Who's resoponsible for "clearing" the stack, the callee (probably) or the called function? Things such as that, anyone? // myclass.h class { public: void abc(); }; // myclass.asm ??? I'm using NASM for assembling and GCC for compiling the C++ code plus linking. "This album was written, recorded and edited at Gröndal, Stockholm in the year of 2000. At this point in time money still ruled the world. Capitalistic thoughts were wide spread. From the sky filled with the fumes of a billionarie's cigar to the deepest abyss drenched in nuclear waste. A rich kid was a happy kid, oh..dirty, filthy times. Let this be a reminder." - Fireside, taken from back of the Elite album Edited by - staffan on June 9, 2001 11:57:43 AM
Advertisement
I wouldn''t recommend implementing a C++ class in assembly. There are a lot of things the compiler takes care of for you (one of those being the this pointer), and doing those things by hand will be a difficult job, IMO. If you really need ASM in your code, I think you can better use inline assembly.

Another reason is that there''s no binary standard for C++ code. That means that every compiler will produce different binary code. Name mangling is often different for each compiler, vtable layout is different, etc.

If you want to see what code the compiler generates, you can use the -S option for gcc. This will produce an assembly file of the compiled code. Maybe that can help you.

HTH


Some useful C++ links:
Free multiplatform ANSI C++ Standard Library implementation
Visual C++ STL fixes
Visual C++ 6.0 noncompliance issues
C++ FAQ Lite
When I think about it, that sounds perfectly reasonable and sound...
I''m probably better off doing it in another way, i.e. using inline assembly (I wanted to bypass this, I don''t speak gas syntax AT ALL ) or calling a pure asm routine from within the method.

Any idea on how gas syntax is like? I guess info will have all the ideas if not...
src,dst operands have their order switch I think? I.e. NASM/MASM/etc. mov dst,src while gas is mov src,dst?

"This album was written, recorded and edited at Gröndal, Stockholm in the year of 2000. At this point in time money still ruled the world. Capitalistic thoughts were wide spread. From the sky filled with the fumes of a billionarie''s cigar to the deepest abyss drenched in nuclear waste. A rich kid was a happy kid, oh..dirty, filthy times. Let this be a reminder."
- Fireside, taken from back of the Elite album
Actually, if no inheritance or such advanced features are used shouldn''t all I had to care about be the this pointer and possibly worry about name mangling (how much could it change it? ELF doesn''t prepend anything to symbol names...Windows compilers do. What else?)?

"This album was written, recorded and edited at Gröndal, Stockholm in the year of 2000. At this point in time money still ruled the world. Capitalistic thoughts were wide spread. From the sky filled with the fumes of a billionarie''s cigar to the deepest abyss drenched in nuclear waste. A rich kid was a happy kid, oh..dirty, filthy times. Let this be a reminder."
- Fireside, taken from back of the Elite album
One option is to do your assembly code using the C calling convention (which is standardised), and then call it from a C method. If you use the extern "C" { ... } specifier for the function prototypes, it should work.

But, as some advice, I would think twice about the reason for using assembly. If you want good performance, designing a good algorithm will work better than doing assembly. I''m not telling you you''re not allowed to do assembly, but I think it''s not worth the hassle, that''s all.

HTH




Some useful C++ links:
Free multiplatform ANSI C++ Standard Library implementation
Visual C++ STL fixes
Visual C++ 6.0 noncompliance issues
C++ FAQ Lite
There doesn''t seem to be a good way of doing it in C or C++, but there is in assembly. It''s no terrible algorithm either...just low level stuff I need to be speedy. I also need to be able to utilize at least the MMX instructions (gcc doesn''t do this per default, of course (there''s a special pentium optimized version of gcc, pgcc, that does however, but not very good to my knowledge)).

Still, I''m interested in knowing if it''s possible and how to implement a method of a class using nothing but assembly. There must be a way... portable and/or standardised or not.

And yes, I did try using C calling convention and having the functions called from inside my method. Something I''d rather not do since the functions are very small and often used. Function calls do take _some_ time...doing two (one rather, with inlining) seems ridiculos. And I suppose it could affect how the processor peforms in general too? I suppose the cache should work wonders here but you never know...

"This album was written, recorded and edited at Gröndal, Stockholm in the year of 2000. At this point in time money still ruled the world. Capitalistic thoughts were wide spread. From the sky filled with the fumes of a billionarie''s cigar to the deepest abyss drenched in nuclear waste. A rich kid was a happy kid, oh..dirty, filthy times. Let this be a reminder."
- Fireside, taken from back of the Elite album
Ugh, why does my posts always seem to die really quickly...
Guess I''ll have to dig out gdb and do a bunch of stack/register dumps from NASM (it comes with nice, already built macros ) if everything else fails...

Well, let''s see what we have so far...
C dumps all return values in eax - this should also be true for C++?
C sends all parameters in reverse order - this should apply to C++ as well, right?
The this pointer should be sent in a register to save cycles... can anyone confirm this?

The real problem seems to be what to call the functions... GCC produces really funny looking names in assembly for methods. Ordinary functions only seems to get __Fxx appended to the tail of their name, where xx is what arguments the function take and F stands for function. so void f() would be called f__Fv.
Anyone knows how it''s like with other compilers? VC? BCC?

Also, does anyone know if MMX and other newer instructions are supported under GAS? My intuition tells me they shouldn''t be but I think I remember pgcc being able to optimize for MMX capable processors - and it should be using gas.

"This album was written, recorded and edited at Gröndal, Stockholm in the year of 2000. At this point in time money still ruled the world. Capitalistic thoughts were wide spread. From the sky filled with the fumes of a billionarie''s cigar to the deepest abyss drenched in nuclear waste. A rich kid was a happy kid, oh..dirty, filthy times. Let this be a reminder."
- Fireside, taken from back of the Elite album
There was some program that converted nasm code to gas, but it didn''t run very well. I only tested it on whole programs at a time, so it might work better on inline.
gas uses the AT&T syntax which is a real pain (haven''t really used it, but I have read some gas code and it doesn''t look fun ).

mov eax, ebx ; Intel syntax
add eax, 1

becomes:

movl %ebx, %eax ; AT&T syntax
addl $1, %eax

or something like that... not at all like Intel syntax (which should be the norm since they made the processors).

There is a program to convert nasm <=> gas. It''s called Intel2gas, have never used it though, so don''t know how well/if it works.

As far as I can remember the thiscall calling convention works like this:

1. return values are widened to 32 bits and stored in EAX (or in EDX:EAX if it is 8 bytes). Floating point return values are stored in ST(0). For returning structs and other large datatypes (larger than 8 bytes) an anonymous variable is used (don''t know if it should be a ''static'' in the function or if the caller provides a space on the stack). IIRC the address to this anonymous variable should be stored in EAX.

2. The ''this'' implicit parameter is passed in ECX.

3. parameter pushing is right to left. All arguments are widened to 32 bits (not sure about arguments larger than that).

4. the called function removes the parameters from the stack (i.e "RET n" where ''n'' is the size in DWORDS of the parameters)

5. certain registers should be saved/restored on entry/exit. EBP at least, possibly ESI and EDI also, don''t really remember, shouldn''t be difiicult to find out though...


Feel free to correct me
(1, 3, 4, and 5 also apply to stdcall)


I think you could have problems with the linker though.

If making the ''completely-asm'' methods virtual is an option then you could make ''new'' and ''delete'' private in the class to prevent them from being used and to provide a function that ''synthesises'' an object, i.e. builds a vtable from scratch etc. This should work quite well because the structure of the vtable and such is fairly fixed (since COM is based on that)). Though you will of course suffer the call-overhead of virtual functions.

This topic is closed to new replies.

Advertisement