BaseAddress

It is time again for something completly off-topic.

In februari I read this msdn article regarding startup time of .Net applications. One of the problems is that every DLL you create in VS will have the same baseaddress causing the LoadImage api to relocate you're dll in memory and run a 'fixup'  routine to change the memory address to match for the new location. You can read this blog from Raymond Chen for some background.

Well that is fixed then, just add a baseaddress for each dll. On that small demo project that will work but for your multi-layer, multi assemblies projects this will be a cumbersome task. Reading through all the available information there is some extra info to take into account. First of all baseAdress start on 64K boundaries and should map into empty process memory space. Determing what empty process space is cannot be calculated during compile time. Only after all dlls are loaded in the process you can run listdlls to get a hint if rebasing was needed. Running listdlls -r [pid] will also show you that some dlls are loaded in your process which depend on the software configuration of the pc. For example the virusscanner software loads a dll in the process on my machine. This makes the problem worse. Not only is it not possible to calculate a rebase free memory space for compile time but also not for all runtime configurations.

Given this I decided to just provide a macro that sets the baseaddress for all your dll projects in your solution. I know this is far from a 100% solution but at least it should fix the rebases on our development box. The macro does not yet take into account definitely blocked addresses but on the next rainy weekend I might improve this macro.

Remember that the BaseAdress setting is bound to the build configuration. You have to run the macro at least for your Debug and Relase config.

In the attachment you find the zip file with the VS Macro.

Imports System
Imports System.IO
Imports EnvDTE
Imports EnvDTE80
Imports System.Diagnostics

Public Module BaseAddress

Sub SetBaseAddress()
Const DllKind As String = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
Const ClassLibrary As String = "2"
Const RebaseTop As Long = &H7F000000
Const DefaultFileLength As Long = &H1000
Dim project As Project

Dim startBase As Long = RebaseTop

If DTE.ActiveSolutionProjects.Length = 0 Then
Exit Sub
End If

For Each project In DTE.Solution.Projects

' only dlls require a base adress
If (project.Kind = DllKind) Then

If (project.Properties.Item("OutputType").Value = ClassLibrary) Then

' this is the initial poor mans memory size calc
' we just taken the filesize of the dll
' so compile your solution before running this macro
Dim CompleteOutputFile As String
CompleteOutputFile = project.Properties.Item("FullPath").Value + _
project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value + _
project.Properties.Item("OutputFileName").Value
Dim opfileLength As Long = DefaultFileLength
If (File.Exists(CompleteOutputFile)) Then
Dim fi As FileInfo = New FileInfo(CompleteOutputFile)
opfileLength = fi.Length
End If
' base adress on 64k boundaries
startBase = startBase - opfileLength
startBase = startBase >> 16 << 16 ' rotate right 16 times and and left 16 times
Debug.Print(String.Format("name:{0} address:{1:x}", project.Name, startBase))
' store the calculated baseadress in the project BaseAddress
' remember this is a Compile config setting. So rerun this if you compile for Release
project.ConfigurationManager.ActiveConfiguration.Properties.Item("BaseAddress").let_Value(startBase)
End If
End If
Next
End Sub
End Module

 

Attachment: BaseAddress.zip
Published 10-07-2006 3:48 PM by Rene Schrieken

Comments

# re: BaseAddress

I think there is a problem with you approach. ;-(

The base address is the physical start address of the native asm code. So a MSIL assembly has to be JITted before the actual 'physical' size can be determined. You might use the same technique (using file size) on native images of your assemblies (using ngen.exe). Native images are usually larger than MSIL assemblies, so you are re-basing, but chances are that conflicts still occur because your size calculation comes up short...

Does this hold any thruth, you'd think?

Tuesday, October 10, 2006 11:01 PM by Marc Jacobi

# re: BaseAddress

There are several problems with my approach. That is the reason I wrote this blog ;-)

You are right with regards to jitting. But the base adress is aslo emitted in the assembly and as far as I could determine the loaded dll's use the baseaddress provided.

The problem gets complexer if you consider that within a solution an assembly might be used by multiple executables (win, console, web or service app) all loading dll's.

Adding to the issue: the baseaddresses can be different on each platform (win2k, winxp, win2k3, vista) and you can rebase dll's your self. There is actually a call for this personalized baseaddressing to fight certain bufferoverflow virus attacks.

So given this complexity (and my conclusion that there is no 100% fit for the problem) is my rude approach good enough or are there serious matters to reconsider?

Rene

Wednesday, October 11, 2006 3:27 AM by Rene Schrieken

Leave a Comment

(required) 
(required) 
(optional)
(required)