Manually defining external symbols with gcc - windows

I'm using DLL injection in a video game for the purpose of modding (I'm building a game API).
I want to directly access structures and variables in the EXE from my new DLL. The absolute addresses of variables are known (the EXE has a fixed image base) .
According the GNU ld documentation, I can use --defsym=symbol=expression to create a global symbol in the output file, containing the absolute address given by expression.
I can't get it to work.
If I declare the symbols as extern in my code, and use ld --defsym, I get undefined reference errors. But if I define the symbols in my code, it just uses the local (DLL) versions, not the EXE ones.
It seems the --defsym options are having no effect. Any insights would be greatly appreciated.
Update: --defsym works perfectly under Linux. When I try compiling on Windows using mingw, I get undefined reference errors.

I've figured out the problem.
After inspecting the assembly produced by mingw, I found the C symbol names are being prefixed by an underscore. This happens on Windows, but not on Linux.
There is a gcc option -fno-leading-underscore, but this results in an undefined reference to WinMain.
Simply adding leading underscores to the symbol names works.
Example: if my my symbol is named alien in C, using gcc --defsym=_alien=0x500000 works fine.

Related

LinkOnceODRLinkage on Windows for global variables

I'm compiling two files with clang 6.0: testA.c and testB.c.
On both files I am running a custom compiler pass that inserts a zero-initialized global variable called globalVarTest. I set the linkage of such global variable to be LinkOnceODRLinkage.
Now, when I link testA.c and testB.c together (that is, the object files obtained by compiling them separately), the linker complains that there are multiple definitions of globalVarTest.
Isn't LinkOnceODRLinkage supposed to tell the linker that if both definitions match, the symbols is the same and it can therefore pick any of the two definitions when building the final executable?
UPDATE:
The same procedure works on Linux. Is this a limitation of the Windows linker? I have been able to achieve the same effect using COMDAT sections but I wonder why LLVM is not using that mechanism automatically without me requiring to explicitly set COMDATS.
I got an answer from the LLVM mailing list. Using LinkOnceODRLinkage does not work on Windows, even though it used to work in the past.
The best way to achieve the same effect is to explicitly use COMDAT sections. Apparently, this is what was happening automatically by setting LinkOnceODRLinkage, until the behavior changed.

Undefined reference to `WinMain' when compiling Nasm program on windows (MinGW)

I would like to compile the Hello World NASM example on windows.
I've pasted the code above into a main.asm file, and compiled it into an obj file with this command:
nasm -fwin32 .\main.asm -o main.obj
After that I wanted to compile this obj file to an exe, like this:
g++ .\main.obj -o main.exe -m32
But I get this error:
C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain#16'
What do I miss? How is it possible to fix this error?
That Hello World program is trying to create the PE import table manually. In order for that to work, you need to instruct the linker carefully (the PE sections are not tied to PE directories, idata is just a name).
Further assumptions are made in that source (e.g. the base address of the image and the need for the CRT).
Honestly, it's just nonsense. Use the linker properly, like Jester shown.
Being really honest, that whole Wikipedia section is just informational at best.
Long story short: never use Wikipedia as a programming tutorial.
EDIT: The x86-64 Linux example on the Wikipedia page has been updated by Peter Cordes; the others may still be misleading.
A bit of brief theory
You can create a 32-bit Windows console program mainly in two ways:
Use the C run time (CRT)
This lets you use the common C functions (above all printf).
There are two ways to use the CRT:
Statically
The object files resulting from the compilation of the CRT source code are linked with the object file resulting from the compilation/assembling of your source code.
The CRT code is embedded entirely in your application.
In this scenario your main function (main/WinMain/DllMain and unicode variants) is being called by the CRT that runs first by a properly set PE entry-point).
In order to use this method you need the CRT object files, these can be found with Visual Studio or MinGW (to name twos).
The order of execution is: The Windows loader calls your PE entry-point, this is set to something like _mainCRTStartup that initialize the CRT and the CRT calls your main function.
Dynamically
The CRT main dll is msvcrt.dll for the version shipped with Windows installation or msvcrtXX0.dll for the version shipped with Visual Studio installation (where XX depends on the VS version).
The CRT dll has the initialization and tear down code in the DLL entry point so by just putting it in the PE import table the CRT is automagically managed.
The order of execution is: The Windows loader loads your PE dependencies, including the CRT DLL (that got initialised as per above) and then call your PE entry-point.
Use only the Windows API
The Windows API are the OS exposed functions, these are what the CRT implementation ends up calling.
You can use the Windows API and the CRT (the common scenario is for a graphical application to have the CRT statically linked and use WinMain as the entry-point - where the Windows APIs are intermixed with C utility functions) or the Windows API alone.
When using them alone you get a smaller, faster and easy to make executable.
To use 1.1 you need the CRT object files and these are usually shipped with a compiler (they once were shipped with the Windows SDK but now that VS is free Microsoft moved them in the VS package - fair but VS is orders of magnitude more heavy than the SDK).
1.2 and 2 don't need these object files.
Note however that compilers/assemblers/linkers compatibility may be a nasty beast, especially the .lib machinery for linking external APIs (basically libs file are a way to make the linker find the functions that will be resolved by the loader at runtime - i.e. those defined in an external DLL).
Hello, world!
Method 2
First, to write Hello, World! using the method 2., see this other answer of mine.
It was written when a linker was available in the Windows SDK, today I use GoLink.
It is a minimalist, very easy to use, linker.
One key point of it is that it doesn't need the .lib files, instead you can pass it the path of the DLLs where the external functions reside.
The NASM command is the same, to link use:
golink /console /entry main c:\windows\system32\kernel32.dll hello.obj -fo hello.exe
Untested - optionally add /largeaddressaware if you code can handle that
That example is for 64-bit programming, it's more involved than a 32-bit one but may be useful anyway.
Method 1.2
This is what the Wikipedia article is trying to use.
Before analyzing that specific code, let me show how I'd write it:
BITS 32
GLOBAL _main
EXTERN printf
EXTERN exit
SECTION .text
_main:
push strHelloWorld
call printf
add esp, 04h
push 0
call exit
SECTION .data
strHelloWorld db "Hello, world!", 13, 10, 0
This is pretty straightforward compared to the Wiki's one.
To make an executable:
nasm -fwin32 helloworld.asm -o helloworld.obj
golink /console /entry _main c:\windows\system32\msvcrt.dll helloworld.obj -fo helloworld.exe
The Wikipedia's code is creating an .idata sections that stores the PE Import Address Table.
This is a silly move, the linker is used to generate that table based on the dynamic dependencies of the object files.
To make that program link we need to:
Tell the linker that the base address is 0x400000. This can be done with any linker (for golink use /base 0x400000).
Tell the linker that the entry-point is where the .text section starts. I don't know if link.exe can take .text as a valid symbol name or if allows to specify an entry-point relative to .text but that seems very unlikely. Golink won't allow for that. In short a label is probably missing.
Tell the linker to make the Import directory points to the .idata section. I'm not aware of any linker that would allow for that (though it may exists).
In short, forget about it.
Method 1.1
This is what the link Jester pointed out is using.
The assembly code is the same as for 1.2 but you use MinGW for linking.

Undefined reference to several OpenMP functions

I was trying to compile an openMP example and he refuses to compile saying "undefined reference to 'OSCR_init', undefined reference to `OSCR_getarg_int' and several other functions. Then I located these functions in the file OmpSCR.h, that came in another folder, searched inside it and saw that these funcions were defined externally, I believe that in omp.h. I included the file with "include " in the example source (OmpSCR.h was already included) hoping that it would solve the question, but nothing improved. I do have omp.h, it came with the os. Can it be a version conflict? I got the example file from OMPSCR_v2.0.tar.gz What should I do?
An "undefined reference" error means that no definition of the function was found at link time. A declaration in a header (such as omp.h) doesn't provide an implementation for the function; it just tells the compiler that the function exists somewhere. You have to link your program with a library that actually provides the function's implementation.
Basically, you just need to link your program to an OpenMP library. The way to do this depends on which compiler and which OpenMP implementation you're using, neither of which you've specified, so I can't provide specifics. (But if you happen to be using GCC, you should use the -fopenmp option for both compiling and linking.)

Need to port Fortran code using the DFWIN module to gcc/gfortran, where do I start?

UPDATE After some digging I found this to be a part of some workaround that passed a file handle from C++ to Fortran using a stub for OPENPIPE. OPENPIPE simply returns an externally declared file handle, doing absolutely nothing with a pipe. OPENHOLDFILENAME actually creates a file, but I'm still confused about what DFWIN has to do with this. Was it required to provide a function declaration for OPENPIPE? If so, they why was it also declared as EXTERNAL in the Fortran code?
I was given the task of compiling legacy Fortran on the GCC toolchain. I've already successfully compiled a few of the source files, but have hit a snag regarding the DFWIN module which links up to some Win32 API functions. It apparently uses some Win32 pipe functions, and I need to replace this with a modern equivalent that works with gfortran (the old compiler was Compaq Visual Fortran).
First, I see the DFWIN module included, as well as some external functions:
USE DFWIN
EXTERNAL OPENPIPE
EXTERNAL OPENHOLDFILENAME
Here is an example of how OPENPIPE is used:
OPEN(UNIT=INN,FILE=
1 '\\.\pipe\input.txt',
1 FORM='FORMATTED',STATUS='old',readonly,
1 USEROPEN=OPENPIPE)
What module can I use to replace these calls on modern Windows/Linux systems using gcc/gfortran?
EDIT: Our priority is to get this running on Windows, but in the future we want to deploy on Linux as well.

mingw, cross-compilation, gcc

Some context:
My program uses libary libfl.a (flex library).
I compile it under linux:
gcc lex.yy.c -lfl
I have mingw compiler installed i586-mingw32msvc-gcc (simple 'hello world' stuff compiles without problem)
I use ubuntu (probably does not matter)
I want to compile under linux for windows (produce binary .exe file which would be usable on windows)
My problem and questions:
When I try compiling my program
i586-mingw32msvc-gcc lex.yy.c -lfl
I get errors:
[...] undefined reference to '_yywrap'
[...] undefined reference to '_WinMain#16'
Do I understand correctly that I have to compile the content of libfl.a also with i586-mingw32msvc-gcc to be able to use it in this cross-compilation?
In the source code there is function yywrap(), but not _yywrap(). Why I get error for function with underscore _?
Whats up with the _WinMain#16? (no usage in source code)
My goal would be to understand what is happening here.
If I get it to work, then its bonus points :)
Any help is appreciated
Yes, certainly. And here's why:
C++ encodes additional semantic information about functions such as namespace/class affinity, parameter types etc. in the function name (that is called name mangling). Thus C++ library names are somewhat different from what you see in the source code. And each compiler does it in it's own way, that's why generally you're unable to link against C++ functions (C function names don't get mangled still) of a library built with a different compiler.
Judging to mangling style, the undefined symbols are brought in by the Microsoft C++ compiler. I don't know exactly about why it needs WinMain, but after you recompile the libs with it, all these errors likely will be gone. And yes: maybe the WinMain() thing rises from msvc using it instead of main(), which presence is obligatory for a well-formed program? ;)

Resources