I'm working on a project with size restrictions, so I don't want to link against Visual Studio's C runtime. I do this with the Static Runtime (/MT), and the /NODEFAULTLIB:LIBCMT flags. I've got most things sorted out by checking the runtime sources that come with VS. However, the compiler still generates some unresolved external symbols:
_chkstk
: Generated to check the stack of a function larger than 4k. Can I turn this off or provide a dummy function?
__libm_sse2_pow
and other SSE calls: I can avoid these by turning off SSE code generation, but I'd like to have them if possible. These symbols seem to come from an Intel lib (libmmd.lib?). Why is this part of the C runtime anyway?
_ftol2_sse
: Convert float to long. I still get this despite turning off SSE code generation.
_CIpow
: Another pow function. I wonder why the compiler generates this instead of the SEE one.
Are there any settings, preprocessor macros or pragmas that control this code generation? I've also tried using msvcrt.lib from visual studio 6.0 SP6, but some functions I use are not working with the VS2010 compiler.
edit:
_chkstk
can be turned off by putting can be found in the CRT source that comes with Visual Studio.#pragma check_stack(off)
in front of the relevant functions.
_CIpow
was a little tougher. It's the intrinsic version of pow which uses a special calling convention. I found no way of turning it off so I ended up reimplementing it in assembler myself. I got some inspiration here: How to: pow(real, real) in x86. I haven't done assembler in a while and this is the first time I'm doing it on the x86. I didn't test it for all cases, so no guarantees! If you have any suggestions for improvement or find a bug, please let me know.
void __cdecl _CIpow(void)
{
// implementation of pow function as 2^(y*log2(x)). this is the
// intrinsic version so base and exponent are already on the fpu
// stack ST0 and ST1. the result is pushed to ST0.
// note that earlier rounding for fist was set to truncate
int temp;
__asm {
// values are repushed, cause fyl2x will overwrite them both
fld st(0) // push ST0 to ST0
fld st(2) // push ST2 (ex ST1) to ST0
fyl2x // ST1 = ST1*log2(ST0), pop ST0
fist temp // assumes truncate rouning
fisub temp // S0 = S0 - temp
f2xm1 // ST0 = (2^ST0)-1
fld1 // push 1 to ST0
faddp st(1),st(0) // ST1 = ST1 + ST0, pop ST0
fild temp // push temp to ST0
fxch // swap ST0 and ST1
fscale // ST0 = inc exp of ST0 by ST1
fxch // put reslut in ST1
fstp st(0) // pop ST0
}
}