I was wondering if it is possible to persuade Visual Studio 2008 (or even 2005) to do C code, but to not wrap the code inside a huge load of nonsense.
Example.c:
int main(){
return 0;
}
becomes
TITLE example.c
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB MSVCRT
PUBLIC _main
; Function compile flags: /Odtpy
; File c:\users\matt\documents\visual studio 2008\projects\mattos2_test\mattos\main.cpp
_TEXT SEGMENT
_main PROC
; int main(){
push ebp
mov ebp, esp
; return 0;
xor eax, eax
; }
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
Which is a 484 byte obj file instead of a 7 byte raw file (which would be 558bec33c05dc3 )
Does anyone know how to turn the c compilation in VS08 to be just that - a c compiler without windows-specific nonsense?
-
-
..euh.. what "huge load of windows-specific nonsense" are you refering to in the above disassembly? I see nothing but 5 machine instructions.
-
Those five machine instructions are the ones I want to be there (and they should be 7 bytes long: 55 8b ec 33 c0 5d c3) but the resulting OBJ file is 484 bytes long, with these particular seven bytes occurring at some fairly arbitrary point half-way through.
My question was how to persuade Vis Studio to not put in the superflous 477 bytes which include everything from the filename of the source-code to "DEBUG" to "Microsoft (R) Optimizing Compiler" and a load of other binary stuffs. -
Have you switched your project to release mode instead of debug?
-
evildictaitor wrote:Which is a 484 byte obj file instead of a 7 byte raw file (which would be 558bec33c05dc3 )
Does anyone know how to turn the c compilation in VS08 to be just that - a c compiler without windows-specific nonsense?
Um, the .OBJ file has more than just code. After some tinkering, I was able to reproduce a 484 Byte .obj (using VS2005), and here is the result of dumpbin:Microsoft (R) COFF/PE Dumper Version 8.00.50727.762
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file WCon_2.obj
File Type: COFF OBJECT
FILE HEADER VALUES
14C machine (x86)
3 number of sections
46B696F0 time date stamp Mon Aug 06 13:35:12 2007
13E file pointer to symbol table
9 number of symbols
0 size of optional header
0 characteristics
SECTION HEADER #1
.drectve name
0 physical address
0 virtual address
2F size of raw data
8C file pointer to raw data (0000008C to 000000BA)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
100A00 flags
Info
Remove
1 byte align
RAW DATA #1
00000000: 20 20 20 2F 44 45 46 41 55 4C 54 4C 49 42 3A 22 /DEFAULTLIB:"
00000010: 4D 53 56 43 52 54 22 20 2F 44 45 46 41 55 4C 54 MSVCRT" /DEFAULT
00000020: 4C 49 42 3A 22 4F 4C 44 4E 41 4D 45 53 22 20 LIB:"OLDNAMES"
Linker Directives
-----------------
/DEFAULTLIB:"MSVCRT"
/DEFAULTLIB:"OLDNAMES"
SECTION HEADER #2
.debug$S name
0 physical address
0 virtual address
7C size of raw data
BB file pointer to raw data (000000BB to 00000136)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42100040 flags
Initialized Data
Discardable
1 byte align
Read Only
RAW DATA #2
00000000: 02 00 00 00 3C 00 09 00 00 00 00 00 35 64 3A 5C ....<.......5d:\
00000010: 44 65 76 65 6C 6F 70 5C 56 53 32 30 30 35 5C 54 Develop\VS2005\T
00000020: 69 6E 6B 65 72 69 6E 67 5C 57 43 6F 6E 5F 32 5C inkering\WCon_2\
00000030: 52 65 6C 65 61 73 65 5C 57 43 6F 6E 5F 32 2E 6F Release\WCon_2.o
00000040: 62 6A 38 00 13 10 01 02 00 00 07 00 0E 00 00 00 bj8.............
00000050: 27 C6 0E 00 00 00 27 C6 21 4D 69 63 72 6F 73 6F 'Æ....'Æ!Microso
00000060: 66 74 20 28 52 29 20 4F 70 74 69 6D 69 7A 69 6E ft (R) Optimizin
00000070: 67 20 43 6F 6D 70 69 6C 65 72 00 00 g Compiler..
SECTION HEADER #3
.text name
0 physical address
0 virtual address
7 size of raw data
137 file pointer to raw data (00000137 to 0000013D)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60500020 flags
Code
16 byte align
Execute Read
_main:
00000000: 55 push ebp
00000001: 8B EC mov ebp,esp
00000003: 33 C0 xor eax,eax
00000005: 5D pop ebp
00000006: C3 ret
RAW DATA #3
00000000: 55 8B EC 33 C0 5D C3 U.ì3À]Ã
COFF SYMBOL TABLE
000 006EC627 ABS notype Static | @comp.id
001 00000001 ABS notype Static | @feat.00
002 00000000 SECT1 notype Static | .drectve
Section length 2F, #relocs 0, #linenums 0, checksum 0
004 00000000 SECT2 notype Static | .debug$S
Section length 7C, #relocs 0, #linenums 0, checksum 0
006 00000000 SECT3 notype Static | .text
Section length 7, #relocs 0, #linenums 0, checksum 96F779C9
008 00000000 SECT3 notype () External | _main
String Table Size = 0x0 bytes
Summary
7C .debug$S
2F .drectve
7 .text.
-
I know that working in .NET has probably spoiled me. I know that I've never worked with low-level code that needs to squeeze out every byte and instruction. All true.
But don't you think that this is a bit of a stretch here? We're not even talking about the final product here, we're talking about overhead inside a temporary OBJ file before linking. Additionally, using a trivial bit of code always gives you a lot of overhead - overhead is often fixed regardless of amount of code involved, so you get skewed results - 6700% overhead! - that don't really mean anything.
In short, why is a 484 byte OBJ file a problem? -
Yggdrasil wrote:I know that working in .NET has probably spoiled me. I know that I've never worked with low-level code that needs to squeeze out every byte and instruction. All true.
But don't you think that this is a bit of a stretch here? We're not even talking about the final product here, we're talking about overhead inside a temporary OBJ file before linking. Additionally, using a trivial bit of code always gives you a lot of overhead - overhead is often fixed regardless of amount of code involved, so you get skewed results - 6700% overhead! - that don't really mean anything.
In short, why is a 484 byte OBJ file a problem?
It's not that there is a huge overhead (although that is also irritating) it's that the executable (.exe) file is not designed to run on any system other than windows - even if the code is not specific to a windows architecture.
I am writing a program to run on a modified x86 processor, which therefore does not have the wonders of windows/linux/unix/mac running on it. The output from the MASM linker seems to put other stuff in which is non-executable and is probably terribly useful for Windows to know, such as information about reallocating the program to another bit of memory, and who compiled it etc - sadly this code is non-executable: If you got an x86 processor, loaded the file into RAM and said "go", the program would not run at all unless the headers are removed.
While efficiency is important (particularly when we are talking about embedded devices) and headers should be removable anyway, this is not the reason for my asking - I am more concerned about the fact that the program simply won't run on an x86 machine while the MASM linker's bloat sits around it.ZippyV wrote:Have you switched your project to release mode instead of debug?
Yes. I've also switched all of the options down to remove things like insertion of libraries etc - the outputted OBJ is normally 4107 bytes long and the resulting executable is about 16087 bytes long.
Re. RichardRudek
Thanks, do you know of anyway of persuading the linker to lose section 1 and 2? They seem to be meta-data for Windows - is there perhaps a way of turning off sections other than the MASM _TEXT section? This might be the problem.
Cheers, and thanks for all your help.
-
evildictaitor wrote:I am writing a program to run on a modified x86 processor, which therefore does not have the wonders of windows/linux/unix/mac running on it.
This is impossible. The Visual C++ compiler can only produce Windows style PE files (which it has to be, because without all that "useless stuff" you're referring to, Windows wouldn't be able to execute the file).
If you're targetting another environment that uses a different executable file format (such as the ELF format used on Linux, which also isn't just plain instructions), you will need a compiler that can target that environment, either with a cross compiler or by compiling in that environment.
Visual C++ isn't going to do what you want, ever.
EDIT: Never mind the fact that before your main function is even invoked some code will run to initialize the CRT, most of which is Windows specific. This code is also linked into the executable file. -
Sven Groot wrote:

evildictaitor wrote:
I am writing a program to run on a modified x86 processor, which therefore does not have the wonders of windows/linux/unix/mac running on it.
This is impossible. The Visual C++ compiler can only produce Windows style PE files (which it has to be, because without all that "useless stuff" you're referring to, Windows wouldn't be able to execute the file).
If you're targetting another environment that uses a different executable file format (such as the ELF format used on Linux, which also isn't just plain instructions), you will need a compiler that can target that environment, either with a cross compiler or by compiling in that environment.
Visual C++ isn't going to do what you want, ever.
EDIT: Never mind the fact that before your main function is even invoked some code will run to initialize the CRT, most of which is Windows specific. This code is also linked into the executable file.
Yes, and that's coded in NASM assembler. It's called a bootloader and it's 512 bytes long. Then there's a secondary bootloader that turns on the A20 gate, switches to VGA mode 3 and then jumps into 32 bit protected mode, and after that the C code can be invoked (I'm not aware of any 16-bit C compilers). I don't want to be unkind, but I'm fully aware that C code doesn't just "run" on a computer. It's not me being an idiot and wondering why "those idiotorz at microsoft have teh huge inefficincies". It's a real problem, albeit one which is rarely encountered.
I am aware that ELF format as well as EXE and OBJ format contain data that is not executable; my contention is that the linker must compile the code from the assembler (generated by the C++/C compiler) into correct machine code, and I would quite like it to stop there.
You suggest that a compiler for operating-system-less environments must be done via a cross-compiler or from within the environment. This is not true. From 32bit windows you can create IL code and x64 code, neither of which will run* on your 32bit windows, but both of which can be created from 32 bit windows
You also suggest that Visual C++ isn't going to be my solution ever, and you'd be correct. I never suggested that I was programming in Visual C++ which requires the C functions new, delete, malloc, free etc, and I was aware that windows forms don't make themselves on screen. I am programming in the C rather than C++ language, and therefore can do pretty much everything that assembler can do - I even get the wonderful __asm{ } block that allows me to strictly do whatever assembler can do (in 32bit protected mode, anyway).
I apologise if I sound like I am getting at you, but the way you phrased your response made it sound like I was asking the question from the point of view of not knowing what I was talking about, which is not true, and not helpful.
Cheers anyway,
Matt.
* IL code is translated to x86 on startup - it isn't natively run.
-
evildictaitor wrote:You suggest that a compiler for operating-system-less environments must be done via a cross-compiler or from within the environment. This is not true. From 32bit windows you can create IL code and x64 code, neither of which will run* on your 32bit windows, but both of which can be created from 32 bit windows
Which is the definition of a cross compiler.
What you need is a compiler capable of creating a binary for your operating-system-less environment. Visual C++ cannot do that. That's unfortunate, but there's not much you and I can do about it.
EDIT: It doesn't make a difference whether you are using C or C++. If you use Visual Studio, it uses the same compiler, cl.exe. If you run it from the command line you'll see it says "Microsoft C/C++ Optimizing Compiler".
Writing your code in Visual Studio is fine, but you will need a different compiler. -
Sven Groot wrote:

evildictaitor wrote:
You suggest that a compiler for operating-system-less environments must be done via a cross-compiler or from within the environment. This is not true. From 32bit windows you can create IL code and x64 code, neither of which will run* on your 32bit windows, but both of which can be created from 32 bit windows
Which is the definition of a cross compiler.
What you need is a compiler capable of creating a binary for your operating-system-less environment. Visual C++ cannot do that. That's unfortunate, but there's not much you and I can do about it.
I mentioned that the processor I am compiling for is an modified (extended) x86 architecture, and everything that comes out of a standard x86 assembler can be run on said x86 processor - I've got a 6,000 lines of NASM here that runs fine, but for obvious reasons getting C to work would be nice - and since I am not developing from Linux, I don't have GCC which is able to compile directly to binary (.bin / .o) file with no headers but also has no IDE.
I mentioned before that I am not using Visual C++, I am using the C compiler inside Visual Studio. That's a big difference. Visual C++ requires the entire of MFC and the standard C libraries. C doesn't.
I think I might have a half-solution:
When the Visual Studio C/C++ compiler is given the following options:
/Od /Oy /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /MD /GS- /Za /J /Zc:wchar_t- /GR- /FAcs /Fa"Debug\\" /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /TC /errorReport:prompt
It outputs a file that doesn't run under windows, and has a 512 block of headers followed by the executable code on the next 512 byte align, 0-padded to the 512 byte align after that. It looks therefore like you can just strip off the first 512 bytes of the outputted file, lose the last zeros (this doesn't actually help, because of 512 byte block-aligning on disks) and then exporting that.
-
evildictaitor wrote:I mentioned before that I am not using Visual C++, I am using the C compiler inside Visual Studio. That's a big difference. Visual C++ requires the entire of MFC and the standard C libraries. C doesn't.
That is not true. All Visual Studio does is invoke cl.exe, it's exactly the same compiler for C and C++. And you most certainly can compile C++ code without linking to MFC (in fact, unless you explicitly create an MFC project, or change the settings yourself, it never links with MFC) or even the CRT. -
Sven Groot wrote:

evildictaitor wrote:
I mentioned before that I am not using Visual C++, I am using the C compiler inside Visual Studio. That's a big difference. Visual C++ requires the entire of MFC and the standard C libraries. C doesn't.
That is not true. All Visual Studio does is invoke cl.exe, it's exactly the same compiler for C and C++. And you most certainly can compile C++ code without linking to MFC (in fact, unless you explicitly create an MFC project, or change the settings yourself, it never links with MFC) or even the CRT.
C++ yes, but then it's not Visual C++. But we're getting off topic here. Do you know of any way to tell the compiler, that is, either the C++ compiler with /Tc option ("compile as C code") or a different C compiler to output code without headers?
-
evildictaitor wrote:When the Visual Studio C/C++ compiler is given the following options:
/Od /Oy /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /MD /GS- /Za /J /Zc:wchar_t- /GR- /FAcs /Fa"Debug\\" /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /TC /errorReport
rompt
It outputs a file that doesn't run under windows, and has a 512 block of headers followed by the executable code on the next 512 byte align, 0-padded to the 512 byte align after that. It looks therefore like you can just strip off the first 512 bytes of the outputted file, lose the last zeros (this doesn't actually help, because of 512 byte block-aligning on disks) and then exporting that.
I was so sure that you can't create a compiled file with the VC++ compiler that would have no PE header... Would that output run in MSDOS?
Have you tried the gcc? -
Does ntoskrnl.exe also have a pe header?
-
ZippyV wrote:Does ntoskrnl.exe also have a pe header?
Yes. The boot cycle of Windows NT is the first-stage bootloader whose job is to load the second stage bootloader, but cannot be more than 512 bytes (one sector). The second stage bootloader sets up a20 gate, 32bit protected mode (and 64bit long mode if 64bit windows), MMU, long memory, VGA graphical mode and the first-chance IDT / GDT labels. This then loads the diskbooter which then loads the third stage bootloader which starts the process handler, thread manager, driver model etc. ntoskrnl.exe is the first process to be called from the process handler, and it invokes all of the drivers and components before windows starts and explorer.exe takes over.
-
ZippyV wrote:Does ntoskrnl.exe also have a pe header?
Yes, it does. -
So how does Microsoft compile those bootloaders? (If they were written in C/C++)
Thread Closed
This thread is kinda stale and has been closed but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.