3

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 #pragma check_stack(off) in front of the relevant functions. can be found in the CRT source that comes with Visual Studio.

_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
    }
}
Community
  • 1
  • 1
maep
  • 1,318
  • 1
  • 12
  • 15
  • What instructions or functions are you using? I am still able to build a "tiny" executable with VS2010 by fiddling with the settings. – Luke Sep 15 '11 at 14:53
  • @Luke: I don't want do redistribute msvcrt100.dll. I can avoid that by either linking against the system's msvcrt.dll (which doesn't work because the `tell()` function fails) or by linking to the static msvcrt.lib which increases executable size by a whopping 200 KB. The above symbols are generated by simple float to long casts and math.h functions. – maep Sep 15 '11 at 18:23

2 Answers2

3

Here's what I had to change from a default Win32 project in VS2010:

Debug

  • C/C++ - Code Generation - Basic Runtime Checks = Default
  • C/C++ - Code Generation - Runtime Library = Multi-threaded Debug (/MTd)
  • Linker - Input - Ignore Specific Default Libraries = libcmtd.lib

Release

  • General - Whole Program Optimization = No Whole Program Optimization
  • C/C++ - Optimization - Whole Program Optimization = No
  • C/C++ - Code Generation - Runtime Library = Multi-threaded (/MT)
  • Linker - Input - Ignore Specific Default Libraries = libcmt.lib

Had to do a few more things to handle the floating point stuff:

  • C/C++ - Command Line = /QIfist (also SetFloatingPointRoundingToTruncate; see link below)
  • extern "C" int _fltused = 1; // a global the compiler defines to load some floating point stuff

I came across an interesting blog post on building minimalist programs with VS where I found some of this information; may have additional tips if you still have problems.

With all of these tweaks I am able to compile and link a program that casts a float to long and invokes some of the pow() functions. The release build is only 3.5 KB, and that includes the embedded manifest.

Luke
  • 11,211
  • 2
  • 27
  • 38
2

I have also worked on a project that compiled with Visual Studio (.NET 2003) without requiring a CRT. More recent versions of VS were more difficult to use and we found it not worth the hacks to get it to work.

Instead you might want to look at minicrt/lictiny. Google use this in Omaha - the auto updater for Chrome and Google Earth.

You also might want to try the MinGW toolchain as this can link to MSVCRT.DLL which is a system component and doesn't need to be distributed by your application.

Bevan Collins
  • 1,531
  • 16
  • 25