JVD
JVD

Reputation: 655

__forceinline generates a function symbol - why ? how to make it not do so?

This code in some header 'a.h' that is multiply included:

    __forceinline void f(void){}
    

Produces a function symbol in every object file that includes 'a.h' - a test object is:

    #include "a.h"
    void f1(void) { f(); }

Compiling this into an object file with Visual Studio 2019 (Community Ed.) v16.10.1 :

$ CL /std:c17 /TC /O2 /c t_inl_a.c
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30037 for x86
Copyright (C) Microsoft Corporation.  All rights reserved.

t_inl_a.c
$
$ DUMPBIN /SYMBOLS t_inl_a.obj
Microsoft (R) COFF/PE Dumper Version 14.29.30037.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file t_inl_a.obj

File Type: COFF OBJECT

COFF SYMBOL TABLE
...
00E 00000000 SECT3  notype ()    External     | _f
00F 00000000 SECT5  notype ()    External     | _f1
...

The MSYS2 binutils 'nm' tool also reports an external ' T f ' symbol.

I am trying to find something in MSVC that is equivalent to GCC's

    __attribute__((always_inline))

, which does NOT generate any function symbol for the above f() function, when the above code is compiled by gcc v11 with __forceinline replaced by attribute((always_inline)), and any -Ox optimization level, x > 0 .

I am much more used to GCC than MSVC.

Would any MSVC expert please be able to point me in the direction of how to generate symbol-less always-integrated-into-caller-function functions with MSVC, when no address of the function is taken in the code, and it is does not take variadic parameters, and is not recursive (conditions under which C standard says that functions are able to be inlined) ?

It does not seem to me to be possible, after hours of scouring the MSVC documentation & web .

To me, the whole point of using __forceline / __attribute__((always_inline))
is that:

A) No symbol is generated, so that one has no multiply-defined-symbol or linkage issues, and does not have to think in what object / library the symbol should be defined in - ( and particularly for Windows, whether it needs __declspec(dllexport) or not ) . There is no symbol, so no concerns associated with symbol linkage .

B) The code is only instantiated when used, consuming 0 bytes if not used

C) No function call / return overhead (the whole point of inline in the first place) - but this saving is somewhat lessened by register save + restore code - (but most function call/return mechanisms also save+restore the registers) .

The approach taken by MSVC would seem to be the worst of both worlds, so one does have to deal with symbol linkage issues and there is always a function symbol generated, taking up space whether it is used or not.

Please can anyone suggest how to disable this function symbol generation for __forceinline declared functions with MSVC ?

Upvotes: 0

Views: 935

Answers (2)

JVD
JVD

Reputation: 655

I guess the "answer" is that MSVC implements inlining with the linker; even though the symbols for __forceinline functions are generated in .obj COFF object files, they are not included in output .EXE or .DLL files ( I checked the /MAP: map files produced ), I guess due to the hidden attributes placed on the function symbols by the compiler. So my bad for not investigating this first - sorry. But it is confusing for anyone used to GCC's way of doing things.

Upvotes: 1

SergeyA
SergeyA

Reputation: 62553

While I can't answer question at hand (I would not know how to force MSVC to avoid generating a symbol), I would like to point out to several misconceptions in your assumptions regarding uses of __forceinline:

  • "No symbol is generated, so that one has no multiply-defined-symbol or linkage issues" - this does not require __forceinline. A plain inline function is guaranteed to not cause ODR violations, regardless of whether actual symbol was created or not.
  • "The code is only instantiated when used, consuming 0 bytes if not used" - it is not clear what you mean by that. If a function is defined (with a symbol), but not called in the code, the symbol will not make it into final executable, so unused functions will not incur space penalty in executable. It is inlined functions which could lead to code bloat, as each invocation of the function will increase executable size by size of the said function.
  • "No function call / return overhead (the whole point of inline in the first place) - but this saving is somewhat lessened by register save + restore code" - the most benefit of inlined function comes not from the call / return, or register manipulation, but from the fact that such function are transparent for optimization purposes. Compiler does not have to make a lot of assumptions on side effects. In fact, this benefit is there regardless of actual inlining, as it is enough for compiler to know of potential side effects or lack of thereof even if an actual call to generated symbol is made.

Upvotes: 0

Related Questions