Closed Brett208 closed 5 years ago
I'm guessing this is a new linker check. This may require a bit of investigation. I haven't found any good documentation on the error message.
You'll note in the errors above, they all refer to non-virtual function calls. It does not list any virtual methods, nor any data exports.
Likely related, is the assembly macros:
%macro Export 2
global %2
section .data
%2 EQU %1-LoadAddr
%endmacro
%macro ExportData 2
global %2
section .data
%2 EQU %1
%endmacro
%macro ExportVirt 2
global %2
section .data
%2 EQU %1
%endmacro
Not all symbols are exported the same way. Note the LoadAddr
offset in the first export
macro. Normal function call addresses are typically encoded within machine instruction as relative offsets, where as virtual function calls and data references use absolute addresses.
Ex (relative addresses used in machine encoding of call instruction):
call Label ; Assembled as: E8 00000000, Jumps to address [EIP + 00000000]
Label: ; Label is at relative offset 0 from the end of the call instruction
Side note: The above might be used to determine the current instruction pointer value in relocatable code. The CALL instruction pushes EIP onto the stack, which can then be popped into a register and used.
In contrast, virtual method calls and data accesses use the absolute form [addr]
.
Ex (a call to a virtual function):
mov eax, ecx ; eax = object.virtualFunctionTablePtr
mov edi, [eax] ; edi = virtualFunctionTable[0] (first virtual method)
call [edi] ; call virtual method
Ex (data access):
mov eax, [dataAddr] ; eax = data
Years ago I'd looked for a way to define a symbol as holding either a relative offset value, or an absolute value, but couldn't find a way. Hence the kludge of subtracting an offset in the first macro, which got added back in during code generation.
One link I came across suggested __declspec(dllexport)
could somehow be used in the C++ header, though I'm not sure it would work in the case here.
Some potentially interesting finds from the NASM documentation:
Absolute segments (not well supported by linkers):
SEGMENT SCREEN ABSOLUTE=0xB800
In 16-bit programming, 0xB800
was the segment address of the screen buffer. By writing to memory in that segment, data would go right to video memory and appear on screen. Perhaps we could use something like that and set:
segment op2exe absolute=0x00400000
Symbols can be accessed WRT
(with respect to) a segment other than normally implied. Perhaps this can be combined with the above.
mov [es:foo wrt data],bx
It's also possible to apply WRT
to EXTERN
declarations:
extern foo:wrt dgroup
For OS/2 support, there are FLAT
segments. I'm uncertain if this feature would be useful for our purposes or not.
Labels can be defined as ABSOLUTE
:
absolute 0x1A
kbuf_chr resw 1
kbuf_free resw 1
kbuf resw 16
The only instructions usable in this mode are the RESB
family, so perhaps not so useful here.
For kicks, I tried compiling with the v120 toolset (toolset packaged with VS2013). Same errors persisted, so if this error was indeed introduced in a later version of VS, it would have been pre-2013.
-Brett
Mildly disturbing, but apparently there isn't a concise list of Visual C++ warnings and errors available online from Microsoft's documentation?
https://stackoverflow.com/questions/1392855/where-can-i-get-a-list-of-all-errors-warnings
EDIT: Actually there is a concise list, but it doesn't seem to contain LNK2016.
By setting the linker option /force, the NetFix dll will actually compile into a DLL even though the errors are still listed on compilation.
We might be able to use /force and then set VS to ignore LNK2016 errors for now and move on.
Attempted to load the new dll with Outpost 2. op2ext gave an error saying NetFix dll could not be loaded.
Found this by googling "LNK2016" Visual Studio BTW. http://forum.outpost2.net/index.php?topic=5315.0
-Brett
Hah, wow, that thread is nearly 8 years old. Didn't realized I'd wanted to make those changes for that long and still haven't. Guess I better get on that. :P
That also explains why you got errors with VS2013 toolset. Even that thread was a few years pre-existing. The original compiler I used is what, 23 years old now? That's probably the compiler we used for the last NetFixClient release.
Anyway, thanks for the investigation. Looks like we can try to get /force
working for now, and maybe silence warnings until we figure out something better.
Just step debugged through op2ext trying to load NetFix with a /force compiled version of NetFixClient in release configuration:
op2ext finds the NetFixClient dll properly (I edited the .ini file to look for the new dll name).
It looks like NetFixClient's main.cpp is entered, and runs until the line:
OPUNetGameProtocol opuNetGameProtocol;
Then the following is thrown:
Exception thrown at 0x034318B0 in Outpost2.exe: 0xC0000005: Access violation executing location 0x034318B0.
The exception is thrown from within the OPUNetGameSelectWnd constructor, on line opuNetTransportLayer.
OPUNetGameSelectWnd::OPUNetGameSelectWnd()
{
opuNetTransportLayer = 0;
...
I don't understand the error as setting a pointer to 0 should not be causing an access violation?
This appears to be the first thing initialized in main besides an Hinstance and maybe an ofstream. So first NetFix specific object to be initiated if that means anything?
Also don't know if this has something to do with an ill formed file by using /force?
-Brett
Very detailed and useful debugging info you posted here.
The line identified by the Visual Studio debugger is likely wrong. As the project was compiled with Release settings, the optimizer will have made changes to the code that can make it difficult for a debugger to determine the source line.
That still narrows it down to somewhere very close though. Combined with the other details may be enough to determine what is happening.
I suspect it's an address problem, where the hardcoded addresses to functions within Outpost2.exe are not matching up correctly. That might be because a module was loaded at an unexpected address, or the offsets done in the macros are wrong, possibly because of changes with the newer compiler version. Some of those changes may be related to the new warnings, and why /force
is now needed.
I suspect the debugger problems were caused by an incorrect setting for LoadAddr
in OP2Internal. The NetFixClient needs a modified value.
Given the project setting change solved the initial errors listed here, should we close this issue?
Current list of errors when attempting to compile NetFixClient with the latest version of OP2Internal: