In this module we will see the C++ .Net from the system programming and to be familiar with the command line tools that available in the VC++ 2003/2005. It is a very long story here. The code snippets (if any) used in this module are for Visual C++ .Net 2003 and if compiled using Visual C++ .Net 2005 you need to use the /clr:oldSyntax option. The following are the topics available in this page
|
Systems Programming
Microsoft Visual C++ .NET is the .NET systems programming language. C++ gives you the facility to do things that are not possible to do in other languages supported by the .NET Framework. If you are the sort of person who wants complete control, Visual C++ .NET is the language for you. In this module we will go into more depth about how .NET works and how you can configure it for your code. The systems concepts of how assemblies are implemented and how to get information about the types that are implemented in assemblies will be explored. Then we will see how assemblies are configured and how you can get configuration information. We will try to learn how code access security protects your code and the implications of writing assemblies in C++ on code access security and we will see the unmanaged API for accessing the runtime and explain how you can use it.
Assemblies
Assemblies are the units of deployment, versioning, and security in .NET, and in this module, we will cover each of these issues. Assemblies can be made up of more than one file, but all code will be contained in the Microsoft Portable Executable (PE) files. Assemblies have to contain metadata (which is vital to how .NET works), and each code file in an assembly will have metadata. One file in the assembly will have information about all the other files in the metadata in a section named the manifest. This file, the one that contains the manifest, is your central point for investigating how assemblies work and the information that they contain.
Portable Executable Files
Code that executes on Windows is stored in a file format known as portable executable (PE), which is an extension of the Common Object File Format (COFF). The PE file format is shown in Figure 1.
Figure 1: The PE file format
A PE file consists of headers containing flags about the file and sections that contain code and data. For historical reasons, all PE files have an MS-DOS header that has a small amount of x86 code that will run under MS-DOS and print out the message “This program cannot be run in DOS mode”. The MS-DOS header can be identified by the two bytes MZ (These are the initials of Mark Zbikowski, one of the original architects of MS-DOS ) at the beginning of the file. The four bytes at location 0x3c within the MS-DOS header are the offset of the PE header from the beginning of the file.
The PE header is made up of two structures, the COFF header and the PE header, and starts with a 4-byte signature, which is PE followed by 2 NULL bytes. The 20-byte COFF header contains information about the type of the machine that the file should be run on, the time and date that the file was created, and the characteristics of the file, which indicate things such as whether the file is a DLL or an EXE. The COFF header also gives the number of sections that are in the PE file. The PE header immediately follows the COFF header, and the size of the PE header is a field in the COFF header. The PE header contains information about:
The version of the linker that was used,
The size of the code and data sections,
The versions of the target operating systems and subsystems, and
Various other flags.
The PE header is 96 bytes followed by the data directory. (The size in the COFF header is the size of the fixed fields plus the size of the data directory.) The data directory contains sixteen 8-byte entries (although the data directory can obtain a different number of entries, current tools generate only 16 entries), where each entry is a relative virtual address (RVA) of the relevant table and the size of the table. An RVA is the location of the item when the file is loaded in memory relative to the load address of the file. You can find the DUMPBIN program in the bin folder of your VC++ compiler shown below (VC++ .Net 2003 and VC++ .Net 2005 Express Edition on Windows XP SP2 machine).
Figure 2: DUMPBIN locations
The values in the PE header can be viewed with the DUMPBIN tool using the /headers switch. For the testing purpose, using VC++ .Net 2005 EE, create CLR Console Application project named Meta1 as shown below. This is a classic Hello World program sample.
Figure 3
Next, run Visual Studio 2005 Command Prompt. So we can use Visual Studio Tools directly at command prompt.
Figure 4
Try running the DUMPBIN tool.
Figure 5
The following example shows the DUMPBIN /headers command against our sample program Meta1.exe.
F:\vc2005project\Meta1\debug>dumpbin /headers Meta1.exe
Microsoft (R) COFF/PE Dumper Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file Meta1.exe
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
5 number of sections
45C73B69 time date stamp Mon Feb 05 22:12:57 2007
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine
OPTIONAL HEADER VALUES
10B magic # (PE32)
8.00 linker version
2200 size of code
6A00 size of initialized data
0 size of uninitialized data
2F04 entry point (00402F04) __CorExeMain@0
1000 base of code
4000 base of data
400000 image base (00400000 to 0040CFFF)
1000 section alignment
200 file alignment
4.00 operating system version
0.00 image version
4.00 subsystem version
0 Win32 version
D000 size of image
400 size of headers
17F64 checksum
3 subsystem (Windows CUI)
0 DLL characteristics
100000 size of stack reserve
1000 size of stack commit
100000 size of heap reserve
1000 size of heap commit
0 loader flags
10 number of directories
0 [ 0] RVA [size] of Export Directory
9454 [ 64] RVA [size] of Import Directory
B000 [ 6A4] RVA [size] of Resource Directory
0 [ 0] RVA [size] of Exception Directory
0 [ 0] RVA [size] of Certificates Directory
C000 [ 258] RVA [size] of Base Relocation Directory
4130 [ 1C] RVA [size] of Debug Directory
0 [ 0] RVA [size] of Architecture Directory
0 [ 0] RVA [size] of Global Pointer Directory
0 [ 0] RVA [size] of Thread Storage Directory
43B0 [ 40] RVA [size] of Load Configuration Directory
0 [ 0] RVA [size] of Bound Import Directory
4000 [ D4] RVA [size] of Import Address Table Directory
0 [ 0] RVA [size] of Delay Import Directory
414C [ 48] RVA [size] of COM Descriptor Directory
0 [ 0] RVA [size] of Reserved Directory
SECTION HEADER #1
.text name
2066 virtual size
1000 virtual address (00401000 to 00403065)
2200 size of raw data
400 file pointer to raw data (00000400 to 000025FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
60000020 flags
Code
Execute Read
SECTION HEADER #2
.rdata name
5AB0 virtual size
4000 virtual address (00404000 to 00409AAF)
5C00 size of raw data
2600 file pointer to raw data (00002600 to 000081FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only
Debug Directories
Time Type Size RVA Pointer
-------- ------ -------- -------- --------
45C73B69 cv 3F 00009168 7768 Format: RSDS, {0709F0EC-FACB-4
13A-9A5A-EDA64266A7EF}, 13, f:\vc2005project\Meta1\debug\Meta1.pdb
SECTION HEADER #3
.data name
6BC virtual size
A000 virtual address (0040A000 to 0040A6BB)
200 size of raw data
8200 file pointer to raw data (00008200 to 000083FF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
C0000040 flags
Initialized Data
Read Write
SECTION HEADER #4
.rsrc name
6A4 virtual size
B000 virtual address (0040B000 to 0040B6A3)
800 size of raw data
8400 file pointer to raw data (00008400 to 00008BFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40000040 flags
Initialized Data
Read Only
SECTION HEADER #5
.reloc name
29A virtual size
C000 virtual address (0040C000 to 0040C299)
400 size of raw data
8C00 file pointer to raw data (00008C00 to 00008FFF)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
42000040 flags
Initialized Data
Discardable
Read Only
Summary
1000 .data
6000 .rdata
1000 .reloc
1000 .rsrc
3000 .text
F:\vc2005project\Meta1\debug>
This tool is just a stub for the linker with the /dump switch. DUMPBIN calls the COFF header file header values, and it calls the PE header optional header values.
The current version of DUMPBIN also describes the fifteenth data directory as the COM descriptor directory; however, this description is likely an artifact from the various names that were used for .NET before the current name was chosen. The ECMA specification calls the fifteenth data directory the CLI header, and confusingly, you can obtain this information with the /clrheader switch to DUMPBIN as shown below.
F:\vc2005project\Meta1\debug>dir
Volume in drive F is hd0c
Volume Serial Number is 98DB-52B1
Directory of F:\vc2005project\Meta1\debug
02/05/2007 10:12 PM <DIR> .
02/05/2007 10:12 PM <DIR> ..
02/05/2007 10:10 PM 23 inputfile.txt
02/05/2007 10:12 PM 36,864 Meta1.exe
02/05/2007 10:12 PM 0 Meta1.ilk
02/05/2007 10:12 PM 306,176 Meta1.pdb
02/05/2007 10:11 PM 25 outputfile.txt
5 File(s) 343,088 bytes
2 Dir(s) 8,525,717,504 bytes free
F:\vc2005project\Meta1\debug>DUMPBIN /CLRHEADER Meta1.exe
Microsoft (R) COFF/PE Dumper Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file Meta1.exe
File Type: EXECUTABLE IMAGE
clr Header:
48 cb
2.05 runtime version
43F8 [ 4D70] RVA [size] of MetaData Directory
0 flags
6000047 entry point token
0 [ 0] RVA [size] of Resources Directory
0 [ 0] RVA [size] of StrongNameSignature Directory
0 [ 0] RVA [size] of CodeManagerTable Directory
91A8 [ 230] RVA [size] of VTableFixups Directory
0 [ 0] RVA [size] of ExportAddressTableJumps Directory
0 [ 0] RVA [size] of ManagedNativeHeader Directory
Summary
1000 .data
6000 .rdata
1000 .reloc
1000 .rsrc
3000 .text
F:\vc2005project\Meta1\debug>
The CLI header gives the RVA for the managed resources and the metadata directory. The managed resource directory holds the resources that you have added to your assembly through the linker /assemblyresource switch. The CLI header also gives the minimum version of the runtime required to run the assembly, but curiously, this version is given as 2.0x. The reason for this odd versioning may be is that .NET was known as COM+ 2.0 during the early part of its development. Immediately after the PE header is a section table that has 40 bytes for each entry. (The COFF header gives the total number of sections). Section is the name of a part of the PE file that can contain either code or data. The section table indicates the name of the section, its size and position in the PE file, and whether the section contains code or data. If the section contains code, the entry in the section header indicates whether the code is readable or writable. Sections in PE files will be located at linker determined alignments. At run time, sections are always loaded at page boundaries. This combination of read/write characteristics and the fact that they are loaded at page boundaries implies that the main purpose of a section is to provide the basic information required by the Win32 virtual memory APIs.
Section names generated by Microsoft compilers always start with a period, but if you define your own sections with #pragma data_seg (for example, to declare a shared data section), you can use any name you want. Section names have a maximum of eight characters, and names longer than this will be truncated. Furthermore, they are not necessarily NULL terminated: the entry in the section table is exactly 8 bytes. The DUMPBIN /headers switch gives this information for each section. The PE header also gives the address of the entry point of the PE file. This code is simply a JMP to either the _CorExeMain or _CorDllMain function exported from mscoree.dll.
Figure 6
This DLL is statically imported by all .NET modules and is the only .NET file that is copied to your machine’s system directory. mscoree.dll is a shim DLL that forwards calls to the appropriate .NET system DLL (mscorwks.dll or mscorsvr.dll). All that described here is true of executable and library assemblies and of .NET module files.