Visual Studio - optimization - remove unused function - visual-studio

I use /opt:ref /VERBOSE option on a Visual Studio 2012 besides having activated "Whole Program Optimization - > Use Link Time Code Generation". /opt:ref is supposed to remove unused functions although I had the impression that specifying "Use Link Time Code Generation" was supposed to remove unused functions by default.
In my test program I use a test function that I expect to be removed from the final executable and VS output seems to confirm that:
Discarded "int __cdecl testMe(int)" (?testMe##YAHH#Z) from Test.obj
But looking over the *.asm file generated with /FAs I can see the function listed:
; Function compile flags: /Ogtp
; File c:\users\g.m\documents\visual studio 2012\projects\Test.cpp
; COMDAT ?testMe##YAHH#Z
_TEXT SEGMENT
?testMe##YAHH#Z PROC ; testMe, COMDAT
...
So, is it removed or not from the final image ?
EDIT:
trivial code to be optimized out
static int testMe(int i)
{
return i + 1;
}
int main()
{
auto res = testMe(0);
}
What I find quite suspicious is even in the case function is "static" it still appears in the *.asm file

What seems to be happening here is that the compiler has not fully optimised out the function at the time it generates the assembly (though you haven't posted the full listing, nor the original function, so it's hard to be sure), but the linker is able to see that it is unreferenced, and has discarded it.
Linking happens after assembly generation, so anything the linker does is not indicated by the intermediate assembly output.
You would know for sure only by looking at the final executable, but I suspect the linker is telling the truth, and has removed your function.
Update:
Testing your code locally confirms my suspicion. The compiler does not optimise out the dead code, but the linker does.

Related

Anyone know the location of SetProcessDpiAwarenessContext() in windows?

I need to turn off DPI scaling in my Win32 application. The recommended way to do this programmatically is via the call:
SetProcessDpiAwarenessContext()
I am using the mingw windows environment. I verified that mingw headers don't have the call, but then several newer calls are missing from the mingw headers. Its a lot of work to update those, I am sure.
I created a local definition of that:
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 3
extern BOOL SetProcessDpiAwarenessContext(int value);
int main()
{
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
}
I still get:
C:\projects\petit_ami>gcc -g3 -Iinclude -Ilibc -static tests/widget_test.c -Wl,--whole-archive bin/petit_ami_graph.a -Wl,--no-whole-archive -lwinmm -lgdi32 -lcomdlg32 -lwsock32 -luser32 -o bin/widget_test
c:/mingw/bin/../lib/gcc/mingw32/9.2.0/../../../../mingw32/bin/ld.exe: bin/petit_ami_graph.a(graphics.o): in function `pa_init_graph':
C:\projects\petit_ami/windows/graphics.c:15662: undefined reference to `SetProcessDpiAwarenessContext'
collect2.exe: error: ld returned 1 exit status
The best documentation I can find says it is in user32.dll.
This is using Windows 10 and recently updated, build: 19042.1052
Thanks for any help.
Scott Franco
San Jose, CA
Almost there. I did:
typedef BOOL (WINAPI *PGNSI)(int);
pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("user32.dll")),
"SetProcessDpiAwarenessContext");
if(NULL != pGNSI) {
dbg_printf(dlinfo, "Procedure found\n");
r = pGNSI(2);
dbg_printf(dlinfo, "r: %d\n", r);
if (!r) winerr();
}
And got:
C:\projects\petit_ami>graphics_test
windows/graphics.c:pa_init_graph():15686: Procedure found
windows/graphics.c:pa_init_graph():15688: r: 0
Error: Graph: Windows error: The parameter is incorrect.
The description of the parameter is here:
https://learn.microsoft.com/en-us/windows/win32/hidpi/dpi-awareness-context
I saw elsewhere that 2 was a valid value, but clearly that may not be correct. The suggestion by Simon to get the Visual studio environment may be operative just to get the proper value. Apologies to Simon, I can't at the moment take the rest of your suggestion. There is a long list of reasons I don't want to bore people with here.
Continued:
I installed and ran the visual studio with sample code. It works, now I am trying to figure out what DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 is, it is not a simple integer.
Anyways, its late. I try to find the final answer tomorrow.
Continued:
The working code is:
/* function call for direct to dll */
typedef BOOL (WINAPI *PGNSI)(int);
/* select for highest DPI */
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 0xfffffffc
...
/* turn off scaling. The following call gets around the lack of a
declaration in mingw */
pGNSI = (PGNSI) GetProcAddress(GetModuleHandle(TEXT("user32.dll")),
"SetProcessDpiAwarenessContext");
if (NULL != pGNSI) {
r = pGNSI(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
if (!r) winerr();
}
As you could probably guess, I am going to tie this to a user option. Now I just need to research what the effect of this new mode is on widgets and other OS features.
Thanks for all the help.
GetProcAddress works and is the recommended method when you cannot be certain if the user's OS will have the function.
If you want to resolve the symbol at link time, you need to ensure that (1) the import library has the symbol, and (2) that the calling convention and name decoration and mangling are correct.
I'm not very familiar with mingw, but I believe it comes with import libraries for some version of common Windows DLLs. Since this is a newer function, it might not be in the import library. There are tools to scan an existing DLL and create a corresponding import library, so perhaps you need to build a fresh one.
The calling convention for Win32 is __stdcall. If your compiler is using a different calling convention by default, you'll have to set it explicitly on your forward declaration of the function. Also, if you're compiling in C++ mode, you'll need to wrap the forward declaration in an extern "C" to prevent name mangling. If either of these are wrong, you'll get an "undefined reference" diagnostic from the linker because the symbol will be "decorated" differently.

C code Optimization by compiler for atmel studio

I am using Atmel Studio 7 and in that, optimization level is -O1.
Can I check what portion of code is being optimized by the compiler itself?
If I am disabling the optimization, my binary file size is of 12KB and on using optimization level -O1, binary file size if 5.5KB.
Can I check what portion of code is being optimized by the compiler itself?
All the code is optimized by the compiler, i.e affected by optimization flags except
It's code that's dragged from libraries (libgcc.a, libc.a, libm.a, lib<device>.a).
Startup code (crt<device>.o) which also includes the vector table, or code from other objects that already exist and are not (re-)compiled in the current compilation. The latter can happen with Makefiles when you change flags therein: If the modules do not depend on the Makefile itself, make will not rebuild them.
Code from assembly modules (*.S, *.sx, *.s) provided preprocessed assembly code does not use conditional assemblation by means of #ifdef __OPTIMIZE__ or similar.
Code in inline assembly, provided the inline asm is not optimized away.
In order to determine whether anything of this is in effect, you can respectively:
Link with -Wl,-Map,file.map and inspect that map file (a text file). It will list which objects have been dragged from where due to which undefined symbol.
Startup code is linked except you -nostartfiles. Add -Wl,-v to the link stage, you'll see crt<device>.o being linked.
You know your compilation units, assembly modules, don't you?
Add -save-temps to the compilation. Inline asm will show in the intermediate *.s file as
/* #APP */
; <line> "<compilation-unit>"
<inline-asm-code>
/* #NOAPP */

How to specify a "clean" name of DLL exports?

I have defined a DLL-export as follows:
__declspec(dllexport)
DWORD WINAPI DllBootstrap(LPVOID addr) {
return 0;
}
Now, using DUMPBIN, the symbol is displayed as follows:
1 0 0001100A ?DllBootstrap##YGKPAX#Z = #ILT+5(?DllBootstrap##YGKPAX#Z)
And this is how the memory looks in Visual Studio:
ยก}....ReflectDLL.dll.?DllBootstrap##YGKPAX#Z..........................................
when inspecting PIMAGE_EXPORT_DIRECTORY.AddressOfNames.
What I need is a clean symbol, i.e., DUMPBIN should output something like:
1 0 0001100A DllBootstrap
and PIMAGE_EXPORT_DIRECTORY.AddressOfNames should point to:
DllBootstrap..........................................
How can I achieve this?
WIN32 BUILDS:
As #RbMm indicated, to retain your function name as-is and get no name decoration, you must use a .DEF file (and remove the __declspec(dllexport) specifier). Then create a DEF file with the line below and either specify it with the /DEF linker option or add it to your Visual Studio project and it will be picked up automatically by the linker:
EXPORTS DllBootstrap
If you don't want to deal with an external .DEF file and you will be using the Visual C++ compiler, the simplest way to limit decoration using just code is to declare your function with 'extern "C"'. This results in decoration including a preceding underscore and appends an "#" along with the argument's byte count in decimal. The following code for example:
extern "C" __declspec(dllexport)
DWORD WINAPI DllBootstrap(LPVOID addr) {
return 0;
}
produces an exported name of:
_DllBootstrap#4
This is how stdcall functions are decorated when C++ name-mangling is disabled with 'extern "C"'. NOTE: WINAPI maps to __stdcall. Retaining 'extern "C"' and changing the convention to __cdecl, you won't get any decoration whatsoever, but module entrypoints should generally remain stdcall as you have it listed in your sample.
If you still want to avoid a .DEF file, there is one last hack you can employ. Add the following line to your code:
#pragma comment(linker,"/EXPORT:DllBootstrap=_DllBootstrap#4")
This will pass an argument to the linker creating a new undecorated name symbol which maps to the decorated name. This isn't very clean as the original name will still exist in your DLL, but you will get your clean exported name.
WIN64 BUILDS (UPDATE):
As Hans Passant commented, for anyone using the Visual C++ 64-bit compiler, there is only the 64-bit calling convention (stdcall, cdecl, etc. keywords are ignored). While C++ mangling will still occur under this compiler, no additional decoration is made to the exported names. In this case, 'extern "C"' would be enough when the sample is compiled as C++ code; if compiled as C, no modifications would be necessary.

Why am I seeing the error "the system cannot find the file specified" in Visual Studio C++?

I am getting an error "the system cannot find the file specified" in Visual Studio C++ when I try to run my program.
You pressed F5 to start the program.
The code was compiled.
The linker failed because it couldn't find int main()
This means there was no program to run.
To fix it you need to define a function called main* that will look like this:
int main (void)
{
// Call the function that you think starts your program, i.e.
Bob();
wprintf(L"Press enter to exit\n");
return fgetc(stdin);
}
The press F7 to make sure it compiles.
Once it has compiled you can use F5 again.
*All C, C++ programs have to have a function called main its the first user visible function that is called. All your code will be called from within main.
Some times main is 'hidden', such as wmain of MFC GUIs, etc.
I can only guess, because you have not given enough information.
Nevertheless, at first I would check the compiling options of the solution and projects for any wrong or missing paths.
If that would not fix the issue, I would check if I have access to all the directories.
Besides, I would avoid using space in any names or paths, because those can cause issues too. I would use camel case notation instead.

Using Linker Symbol from C++ code as a fixed constant (NOT relocated) in a shared library (DLL)

Sorry if the title is not very clear. I am using MinGW with GCC 6.3.0 to build a x86 32-bit DLL on Windows (so far). I'll spare you the details why I need hacky offsets amongst its sections accessible from code, so please do not ask if it's useful or not (because I don't want to bother explaining that).
So, if I can get the following testcase to work, I'm good. Here's my problem:
In a C++ file, I want to access a linker symbol as an absolute numeric value, not relocated, directly. Remember that I am building a 32-bit DLL which requires a .reloc section for relocations, but in this case I do NOT want relocation, in fact a relocation would screw it up completely.
Here's an example: retrieve the offset of say __imp__MessageBoxW#16 relative to __IAT_start__, in case you don't know what they are, __imp__MessageBoxW#16 is the relocated pointer to the actual function at runtime, and __IAT_start__ is a linker symbol in the default script file. Here's where it is defined:
.idata BLOCK(__section_alignment__) :
{
/* This cannot currently be handled with grouped sections.
See pe.em:sort_sections. */
KEEP (SORT(*)(.idata$2))
KEEP (SORT(*)(.idata$3))
/* These zeroes mark the end of the import list. */
LONG (0); LONG (0); LONG (0); LONG (0); LONG (0);
KEEP (SORT(*)(.idata$4))
__IAT_start__ = .;
KEEP (SORT(*)(.idata$5))
__IAT_end__ = .;
KEEP (SORT(*)(.idata$6))
KEEP (SORT(*)(.idata$7))
}
So far, no problem. Because GAS doesn't allow me to "subtract" two externally defined symbols (both symbols are defined in the linker), I have to define the symbol in the linker script, so at the end of the linker script I have this:
test_symbol = ABSOLUTE("__imp__MessageBoxW#16" - __IAT_start__);
Then in C++ I use this little inline asm to retrieve this relative difference which is supposed to be a fixed value once linked:
asm("movl $test_symbol, %0":"=r"(var));
Now var should contain that fixed number right? Wrong!
Because test_symbol is an "undefined" symbol as far as the assembler is concerned, it makes it relocated. Or I don't know why, but I tried so many things to force it to be an "absolute constant value symbol" instead of a "relocated symbol" to no avail. Even editing the linker script with many things like LD_FEATURE("SANE_EXPR") and others, doesn't work at all.
Its value is correct only if the DLL does not get relocated.
You see, either GNU LD or the assembler adds an entry in the .reloc section for that movl instruction, which is WRONG!
Is there a way to force it to treat an external/undefined symbol as a fixed CONSTANT and apply no relocation to it whatsoever? Basically, omit it from the .reloc section.
I am going crazy with this, please tell me there's something easy I overlooked, I searched for hours!
In other words, is there a way to use a Linker Symbol from within inline asm/C++ without having it relocated whatsoever? No entry to the .reloc section or anything, basically same as a constant like $1234. So if a DLL gets loaded into another base address, that constant would be the same everytime.
UPDATE: I forgot about this question but decided to bring an update, since it seems it's likely not possible as nobody even commented. For anyone else in the same boat as me, I presume this is a limitation of the COFF object format itself. In other words, external symbols are implicitly relocated, and it doesn't seem there's a way against this.
I didn't "fix" it the way I wanted, I did it in a very hacky way though. If anyone is interested, here's my ugly "hack":
First I put a special "custom" instruction in the inline assembly where I reference this external symbol from C++. This "custom" instruction holds a placeholder instruction that grabs the symbol (normal x86 asm instruction with a dummy constant, e.g. 1234) and a way to identify it. Then let GCC generate the assembly files (.S files), then I parse the assembly with a simple script and when I find that "custom" instruction I insert a label for the linker (make it .global) and at the same time add a directive to a custom "on-the-fly" generated linker script that gets included from my main linker script at the end.
This places data in a temporary section in the resulting DLL with absolute offsets to the custom instruction that I need, but without relocation.
Next, I parse the binary DLL itself, in particular that temporary section I added with all this hack. I take the offsets from there, convert them to file offsets, and modify the DLL's .text section directly where those offsets point (remember those placeholder instructions? it is replacing their immediate constants 1234 with the respective value from the linker's non-relocated constant). Then I strip the temporary section from the DLL, and it's done. Of course, all of this is done automatically by a helper program and script
It's an insane hack, but it works and it's fully automatic now that I got it going. If my assumption is correct that COFF doesn't support non-relocated external symbols, then it's really the only way to use linker constants from C++ without them being relocated, which would be a disaster.

Resources