Symbol Visibility in Windows - c++

I do a lot of programming in linux and I use the visibility attribute to define if a symbol is visible or hidden in the Shared Object. Just to make the things clearer possible: If a symbol is visible it will be accessible externally (someone linking with the shared object), if it is hidden it is supposed to be used only internally.
On windows it seems to work a bit different, it works with exporting (the symbol is defined here in the shared object and will be accessible by someone linking with this) and importing (here I am linking with a shared object and the symbol is exported there) symbols. But I couldn't find a way to tell the compiler to not export a symbol because it must be used only here, i.e. if someone link with it a linker error is expected.
My question is if I can define a symbol as "hidden" (like in linux's gcc) and how.
Also, all this visibility in windows topic is a bit fuzzy for me and I was looking for some further reading links to understand better how everything works.

David Rodriguez is correct, in the MSVC environment the programmer typically explicitly exports function/class symbols via the MSVC-specific __declspec(dllexport) modifier. Symbols that aren't explicitly exported shouldn't show up in the symbol table for the compiled DLL (you can use dumpbin, one of the Visual Studio command line utils, to verify, using the /EXPORTS option). It is convention to use dllimport when you import that symbol, although I believe this is optional. How this typically plays out is that header files defining the public interface of a DLL will have some macro that expands to __declspec(dllimport) by default, but is set to expand to __declspec(dllexport) while that library is being built.
Note that how GCC and MSVC treat dllexport may be different; perhaps GCC doesn't 'respect' dllexport in the sense of hiding unexported symbols? I would first try compiling with MSVC and test those results with dumpbin before trying the same with GCC. If you don't have Visual Studio, you can still get a MSVC compiler by either downloading VS Express, or (less known) by downloading certain .NET redistributables which ship with command line MSVC (both these options are free and legit). VS Express may be the better choice here so you can get dumpbin.

Related

Problems enabling RTTI in LLVM JIT-ed code

I'm JIT-ting C++ code in a Windows application. I'm using LLVM/CLang 5.0, and the application was compiled using MsVc 2015.
While DLLs and executable code created with the two toolchains mix and match very well, I'm facing problems with the JIT-ted code that doesn't include variables that LLVM should generate automatically, like ??_7type_info##6B# and associated stuff, like \01??_R0H#8. They are registered as external only, and any use of them will cause the application to crash with
LLVM ERROR: Program used external function '??_7type_info##6B#' which could not be resolved!
While I have found examples of adding user-defined variables to JIT-ted code, I could not find effective solutions to the problem of making JIT code refer to these internal variables, that are generated behind the curtains.
I believe I could provide the missing variables via a DLL compiled with CLang, with the tweaking of .ll but I would prefer a cleaner solution, merely configuring the JIT-ter engine.
Can anybody help me, please ?
??_7type_info##6B# is the mangled name of the vtable for the std::type_info class, which is provided by one or other of the MSVC static libraries that gets linked implicitly, for example:
c:/Program Files (x86)/Microsoft Visual Studio/2017/Professional/VC/Tools/MSVC/14.15.26726/lib/x64/msvcrt.lib
To fix the LLVM lookup error you can export this symbol from your own DLL or EXE, and you can actually do this from your C++ code like this:
#pragma comment(linker, "/export:??_7type_info##6B#")
See also https://learn.microsoft.com/en-us/cpp/build/reference/export-exports-a-function?view=vs-2017
You may also have to call the utility function below to ensure all your symbols are visible to LLVM
llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr);
Not sure if that's strictly necessary in this case, but it's recommended by the LLVM JIT compiler tutorial.

Xcode - bundle too large

I have one C++ project, it's a dynamic lib. When I compile it on Windows (Visual Studio 2012) its 300 kB large. But when I compile it on Mac with XCode, it has 3.9 MB binary inside the bundle.
I have the optimization level Fastest, Smallest [-Os] option selected.
Debug symbols are also turned off.
The project are the same, the only extra framework is Cocoa.framework, which I need to sucessfuly compile the project. Could Cocoa.framework link so much?
Is this some bad linker's work?
I can compile this with LLVM GCC 4.2 or Apple LLVM Compiler 4.2, the size is the same.
Any ideas how to reduce the .bundle size?
I'd hazard a guess this is occurring due to exported symbols from your project. We're not talking about debug symbols here, but symbol table entries for every class, method, constructor, exception-handler unwind segments and so on. The latter category accounts for a lot of them in a project using exceptions and the standard library.
If you're using STL, boost or anything else with a lot of templates, you'll also have the specialisations for every type you used them with (often the entire class - not just methods), with weak linkage. The length of symbols-names gets huge with template expansion and C++ name mangling of parameter types.
When compiling windows DLLs, symbols must be explicitly exported - either using compiler directive (often using the DLLExport macro) or a linker symbol export list.
On MacOSX and ELF-based *NIX systems it's the other way around: they're all exported by default. The linker has no way of knowing what the module might be linked to, and therefore which ones are useful or not. In reality, an application usually only really need to export main and any unresolved symbols.
There is also no distinction for C++ class members marked as private. You get the symbols for these too.
This reference from Apple describes how to limit visibility of symbols. You certainly used to be able to do this with gcc - but a quick look at the equivalent for clang suggests it's not as well supported there.
The inflated binary size is the result of compiled binary having debugging symbols.
Go to "Project"/"Edit Project Settings" menu item, click on build tab, under "Code Generation" section, uncheck Generate Debug Symbols. You can type in "sym" in search field to help find it.

External symbol resolving in a dll

I'm working on a cross-platform c++/qt project with a plugin system, we are using so files on linux and dll on windows. We are using gcc on Linux and Visual Studio 2010 on Windows through cmake.
The problem is our plugins sometimes need to call a function from the application source code, which is working fine on Linux with gcc by just including the header files. But on Visual Studio, we got unresolved external symbol errors.
Is it because so and dll files works differently?
thank you.
The default behaviour for exporting symbols from dlls on Windows is exactly opposite: by default, symbols are invisible, you need to export them explicitly. With VC++ this is done by __declspec(dllexport) declarators.
EDIT (Information added): You are entering a region of non-standardized, system specific behaviour... There are much more problems associated with writing cross-platform "pluggable" component systems in C++ than you might be expecting. On Windows there are so called import libraries, which define all symbols exported from a dll. You have to link against these libraries in order to resolve these symbols. This is called implicit linking. You can also link explicitly which means loading dll and its exported symbols at run-time. However all these are just technical details compared to so called binary compatibility issues, which will almost certainly kill you, if not considered during the design of your component system.
I am wondering about one thing: You said you're using Qt. Qt application framework has got it's own cross platform conventions and rules for writing and building pluggable components. Why don't you stick with these...?

Calling Conventions in Visual Studio

I have a fortran DLL built in the CVF convention and my c++ code built using cdecl calling convention to get the stuff it needs from my DLL. I checked in my c++ code obj files and the symbols are '_imp_variable'. Then in my fortran dll the symbol shows up as 'variable'. I got some linker errors (unresolved external symbol _imp_variable), is it because c++ is looking for '_imp_variable' exactly as is in my DLL? Or does VS cdecl calling convention just adds stuff weirdly but it knows to look for 'variable'?
Prefix __imp__ is added by __declspec(dllimport) storage-class attribute. It means that object or function is imported from DLL using import library (usually created by linker on DLL build). Make sure you added such library to your project.
If for unknown reason you don't have import lib or DLL sources take a look here: http://support.microsoft.com/kb/131313

Suppress import library creation - Visual C++ linker

Is there, a perhaps undocumented way to prevent linker from creating IMPLIB for a DLL or an EXE, despite having __declspec(dllexport) directives within the source code?
Specifying no /IMPLIB results in .LIB created with a default name.
This is important when the declspec directives arrive from 3rd party code which is not under control. This is, for example, the case with boost::serialization. A possible solution would be a way to "undeclare" a DLL export. DEF file also cannot do it (AFAIK), because it can only add to the export list but not remove from it.
Many 3rd party code does not use __declspec(dllexport) directly, but hides it under a macro in order to control it. Typically they want to switch between dllexport and dllimport depending on where the header file is included (inside the dll implementation or by the user of the dll)
If that is the case in the library you try to include it should not be too difficult to alter this behavior via macro manipulation to meet your exact needs.
For example, boost::serialization check the config.hpp and see how you can control it.
According to this, if you supply the .exp file when linking, the linker will not create a .lib file. To be honest, though, I can't tell if this helps in your case.
There is not any way to do this with a linker option, using /implib:"nul" fails miserably when the linker uses it to name the .exp file. The most practical solution is to remove the files again after a build. Project + Properties, Build Events, Post-Build event and paste:
del $(TargetDir)$(TargetName).lib
del $(TargetDir)$(TargetName).exp
Using a .def file containing your exported functions marked with the PRIVATE keyword will tell the linker to skip placing the symbol in your import library.
Refer to this MSDN page for more information about MSVC's .def file syntax.
Nowadays, you can use /NOIMPLIB and /NOEXP in the advanced linker options as per this bug ticket. Works for me on Visual Studio 2019.