I'm trying to determine Visual Studio version (2002/2003, 2005, 2008, 2010, 2012, 2013, 2015) from the .obj
file generated with the link time code generation option.
The file I have, generated with MSVC2012, has following COFF header contents:
File Header
+0 00 00 Machine - Unknown Machine
+2 FF FF NumberOfSections
+4 01 00 4C 01 TimeDateStamp
+8 70 94 F9 55 PointerToSymbolTable
+12 38 FE B3 0C NumberOfSymbols
+16 A5 D9 SizeOfOptionalHeader
+18 AB 4D Characteristics
Optional Header
+20 AC 9B Magic
+22 D6 B6 Linker Version Major/Minor
It seems that the initial 4 bytes being 00,00,FF,FF mark it as a LTCG object, and what follows is proprietary. None of the usual file header members make "sense" (maybe the timestamp is OK, I didn't check).
Does anyone know offhand if any part of this header is compiler-specific? All I need to determine is the MSVC major version used to compile the object...
It appears that there is a version, coded as <MAJOR:16:LE> 0x80 <MINOR:16:LE>
, stored shortly after the header. E.g.:
17.00.61030 -> 0x11.0xEE66 -> 11 00 80 66 EE
19.00.23026 -> 0x13.0x59F2 -> 13 00 80 F2 59
What's needed is to figure out how to get to it reliably by offsets from preceding data.
This is a related question, with no resolution...
TL,DR :
You can't get the compiler version with this file format, I guess ...
Complete answer :
It looks like some variation of the "anonymous file format", described in the "winnth.h" by various ANON_OBJECT_HEADER_XXX
structures (replace XXX
by V2
or BIGOBJ
).
Here is a copy of the ANON_OBJECT_HEADER_BIGOBJ
found in winnt.h :
typedef struct ANON_OBJECT_HEADER_BIGOBJ {
/* same as ANON_OBJECT_HEADER_V2 */
WORD Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
WORD Sig2; // Must be 0xffff
WORD Version; // >= 2 (implies the Flags field is present)
WORD Machine; // Actual machine - IMAGE_FILE_MACHINE_xxx
DWORD TimeDateStamp;
CLSID ClassID; // CLSID is a 16 bytes struct (not original comment)
DWORD SizeOfData; // Size of data that follows the header
DWORD Flags; // 0x1 -> contains metadata
DWORD MetaDataSize; // Size of CLR metadata
DWORD MetaDataOffset; // Offset of CLR metadata
/* bigobj specifics */
DWORD NumberOfSections; // extended from WORD
DWORD PointerToSymbolTable;
DWORD NumberOfSymbols;
} ANON_OBJECT_HEADER_BIGOBJ;</code>
The description match:
Sig1 : 00 00
Sig2 : FF FF
Version : >=2
Machine : 0x14c`
The other header structures (i.e, ANON_OBJECT_HEADER
and ANON_OBJECT_HEADER_V2
) are basically the same, but with less fields.
For the Version
field, I found some information here :
http://www.geoffchappell.com/studies/msvc/link/dump/infiles/obj.htm
Looks like the Version
field is "1" for anonymous files, and it seems like the anonymous files and the so called "import files" shared the same characteristics, only that Version = 0
for import file format (I do not really know what it is admittedly).
But yeah, by just looking at the header, it seems that we have no information on what compiler version was used. And even then, when looking at .obj files generated with the /GL switch, they do not exactly follow this format and I didn't find much information about them. I'll be glad that someone prove me wrong.