Friday, January 15, 2010

Mac OS Stack alignment – What you may need to know

While I let my little tirade continue to simmer, I figured many folks’ next question will be “Ok, so there may be something here that affects me. What do I need to do?” Let’s first qualify who this will affect. If you fall into the following categories, then read on:

  • I like to use the built-in assembler to produce some wicked-fast optimized functions (propeller beanie worn at all times…)
  • I have to maintain a library of functions that contain bits of assembler
  • I like to take apart my brand new gadgets just to see what makes them tick (Does my new 802.11n router use an ARM or MIPS CPU?)
  • My brain hasn’t been melted in a while and I thought this would be fun
  • I want to feel better about myself because I don’t really have to think about these kinds of things

Let’s start off with a simple example. Here’s an excerpt of code that lives down in the System.pas unit:

function _GetMem(Size: Integer): Pointer;
asm
TEST EAX,EAX
JLE @@negativeorzerosize
CALL MemoryManager.GetMem
TEST EAX,EAX
JZ @@getmemerror
REP RET // Optimization for branch prediction
@@getmemerror:
MOV AL,reOutOfMemory
JMP Error
@@negativeorzerosize:
XOR EAX, EAX
DB $F3
end;

Notice the CALL MemoryManager.GetMem instruction. Due to the nature of what that call does, we know that it is very likely that a system call could be made so we’re going to have to ensure the stack is aligned according to the Mac OS ABI. Here's that function again with the requisite changes:


function _GetMem(Size: Integer): Pointer;
asm
TEST EAX,EAX
JLE @@negativeorzerosize
{$IFDEF ALIGN_STACK}
SUB ESP, 12
{$ENDIF ALIGN_STACK}
CALL MemoryManager.GetMem
{$IFDEF ALIGN_STACK}
ADD ESP, 12
{$ENDIF ALIGN_STACK}
TEST EAX,EAX
JZ @@getmemerror
REP RET // Optimization for branch prediction
@@getmemerror:
MOV AL,reOutOfMemory
JMP Error
@@negativeorzerosize:
XOR EAX, EAX
DB $F3
end;

When compiling for the Mac OS, the compiler will define ALIGN_STACK so you know that this compile target requires stack alignment. So how did we come up with the value '12' in which to adjust the stack. If you remember from my previous article, we know that upon entry to the function, the value in ESP should be $xxxxxxxC. Couple that with the fact that up until the actual call, we've done nothing to change the value of ESP, we know where the stack is in the alignment. Since the stack always grows down in memory (toward lower value addresses), we need change ESP to $xxxxxxx0 by subtracting $C, which is 12 decimal. Now the call can be made and we'll know that upon entry to MemoryManager.GetMem, ESP, once again, will be $xxxxxxxC.


That was a relatively trivial example since there was only one call out to an function that may make a system call. Consider a case where MemoryManager.GetMem was just a black-box call and you had no clue what it would actually do. You cannot ever be certain that any given call will not lead to a system call, so the stack needs to be aligned to a known point just in case the system is called.



Another point I need to make here is that if the call goes across a shared library boundary,  even if the shared library is also written in Delphi, you will be making a system call the first time it is invoked. This is because all function imports, like Linux, are late-bound. Upon the first call to the external reference, it will go through the dynamic linker/loader that will resolve the address of the function and back-patch the call site so that the next call goes directly to the imported function.


What happens if the stack is misaligned? This is the most insidious thing about all this. There are only certain points where the stack is actually checked for proper alignment. The just mentioned case where you’re making a cross-library call is probably the most likely place this will be encountered. One of the first things the dynamic linker/loader does is to verify stack alignment. If the stack is not aligned properly, then a mach EXC_BAD_ACCESS exception is thrown (this is different than how exceptions are done in Windows, see Eli’s post related to exception handling). The problem is that the stack alignment could have been thrown off by one function, hundreds of calls back along the call chain! That is really “fun” to track down where it first got misaligned.


Suppose the function above now had a stack frame? What would the align value be in that case? The typical stack frame, assuming no stack-based local variables, would look like this:


function MyAsmFunction: Integer;
asm
PUSH EBP
MOV EBP,ESP
{ Body of function }
POP EBP
end;

In this case the stack pointer (ESP) will contain the value, $xxxxxxx8 which is 4 bytes for the return address and 4 bytes for the saved value of EBP. If no other stack changes are made, surrounding any CALL instruction, assuming you’re not pushing arguments onto the stack which we’ll cover in a moment, there would be a SUB ESP,8 and ADD ESP,8 instead of the previous 12.


Now, this is where it gets complicated, which clearly demonstrates why compilers are pretty good at this sort of thing. What if you wanted to call a function from assembler that expected all the arguments too be passed on the stack? Remember that at the call site (ie. just prior to the CALL instruction), the stack must be aligned to a 16 byte boundary and contain $xxxxxxx0. In this case you cannot simply push the parameters on the stack and then do the alignment. You must now align the stack before pushing parameters onto it knowing how the stack will be aligned after all the parameters are pushed. So if I need to push 2 DWORD parameters onto the stack and the current ESP value is $xxxxxxxC, you need to adjust the stack by 4 bytes (SUB ESP,4). ESP will now contain $xxxxxxx8. Then push the two parameters onto the stack which adjusts ESP to $xxxxxxx0, and we’ve satisfied the alignment criterion.


If the previous example had required 3 DWORDS, then no adjustment of the stack would be needed since after pushing 3 DWORDS(that’s 12 bytes), the stack would have been $xxxxxxx0, and we’re aligned. Likewise, if the above example had required 4 DWORD to be pushed, then now we’re literally “wasting” 12 extra bytes of stack. because 4 DWORDS is 16 bytes, that block of data will naturally align, so we have to start pushing the parameters on a 16 byte boundary. That means we’re back to adjusting the stack by the full 12 bytes, pushing 16 bytes onto the stack and then making the call. For a function call taking 16 bytes, we’re actually using 28 bytes of stack space instead of only 16! Add in stack-based local variables and you can see how complicated this can quickly get.


Remember, this is also happening behind the scenes within all your Delphi code. The compiler is constantly keeping track of how the stack is being modified as the code is generated. It then uses this information to know how to generate the proper SUB ESP,ADD ESP instructions. This could mean that code that was deeply recursive that worked fine on Windows, would now possibly blow out the stack on the Mac OS! Yes, this is admittedly a rare case since stacks tend to be fairly large (1MB or more), but it is still something to consider. Consider changing your recursive algorithm to iterative instead in order to keep the stack shallower and cleaner.


You should really consider whether or not your hand-coded assembler function needs to be in assembler and if it would work just as well if it were in Pascal. We’re evaluating this very thing, especially for functions that are not used as often or have been assembly merely due to historical reasons. Like you, we also understand that there is a clear benefit to having a nice hand-optimized bit of assembler. For instance, the Move() function in the System unit was painstakingly optimized by members of the FastCode project. Everyone clearly benefits from the optimization that function provided since it is heavily used throughout the RTL itself, but also by many, many users. Note here that the Move() function required no stack alignment changes since it makes no calls outside its own block of code, so it is just as fast and optimized as before. It runs unchanged on all (x82-32bit) platforms.

Thursday, January 14, 2010

It’s my stack frame, I don’t care about your stack frame!

I’m going to start off the new year with a rant, or to put it better, a tirade. When targeting a new platform, OS, or architecture, there will always be gotchas and unforeseen idiosyncrasies about that platform that you now have to account for. Sometimes they are minor little nits that don’t really matter. Other times they can be of the “Holy crap! You have got to be kidding me!” Then there are are the “Huh!? What were they thinking!?” kind. For the Mac OS running on 32bit x86 hardware, which is what we’ll be supporting initially while we’re still getting our x64 compiler online, we encountered just that sort of thing. I’m probably going to embarrass myself here. I’ve worked with the x86 CPU architecture for at least 25 years, so I would hope that I’ve got a pretty good handle on it. I also work with a bunch of really smart people that have the same, if not more experience, with the x86 and and other RISC/CISC architectures. These are not just folks that have worked with those architectures, but create compilers and tools for them, including back-ends that have to generate machine instructions. I don’t know, but I’d venture a guess that you have to have more than a cursory knowledge of the given CPU architecture.

So what did we find that would prompt me to go on a tirade? It seems that the MacOS ABI* requires that just prior to executing a CALL instruction, we must ensure that the stack is aligned to a 16byte (Quad DWORD) boundary. This means that when control is transferred to a given function, the value in ESP is always going to be $xxxxxxxC. Prior to the call, it must be $xxxxxxx0. Note that Windows or even Linux doesn’t have this requirement. OK? The next question is “Why!?” Let’s examine several potential scenarios or explanations. I, along with my colleagues here at Embarcadero (and even past Borland/CodeGear colleagues that now literally work at Apple) have yet to have this explained to our satisfaction. We even know one that even works at Apple on the Cocoa R&D team in the OS group! Our own Chris Bensen, has even visited these friends for lunch at Apple and posed the question.

By now you’re either thinking I’ve gone around the bend, or what is the big deal? Others are probably thinking, “Well that makes sense because modern CPUs work better if the stack is aligned like that.” Here are some various reasons we’ve both come up with ourselves and explanations we’ve been given. They all tend to be variations on a theme but none have truly been satisfactory.  Why burden every function in the system to adhere to this requirement for some (in the grand scheme) lesser used instructions.

“The Mac OS uses a lot of SSE instructions”

Yes, there are SSE instructions that do require that all memory data be aligned on 16 byte boundaries. I know that. I also know that many CPU caches are 16 bytes wide. However, unless you are actually using an SSE instruction (and face it, most functions will probably never actually use SSE instructions). What I do know about alignments is that for a given machine data size (1, 2, 4, 8, 16 bytes), they should always be aligned to their own natural boundary for maximum performance. This also ensures that a memory access doesn’t cross a cache line, which is certainly more expensive.

But why does my function have to make sure your stack is aligned? What I mean is that if a compiler (or even hand coded assembly) needs to have some local variable or parameter aligned on the stack, why doesn’t the target function ensure that? I refer you to the title of this post for my feeling on this one. If you need it aligned, then align it yourself.

“The Mac OS intermixes 64bit and 32bit code all over the place”

I’ve heard this one a lot. Yes, x86-64 does have stricter data alignment requirements, but intermixing of the code? Does it? Really? Not within a given process, AFAIK. When you call into the OS kernel, the CPU mode is switched. Due to the design of 64bit capable CPUs, you cannot really execute 64bit code and 32bit code within the same process. And even if the kernel call did cause a mode switch and used the same stack, I again, refer you to the title of this post. Admittedly, I don’t know all the gory details of how the Mac OS handles these 32bit<->64bit transitions. I would imagine that they would have to go through a call gate since the ring has to change along with the “bitness” mode. This will also typically cause a switch to a different “kernel stack” which would also copy a given number of items from the user’s stack. This is all part of the call descriptor.

“It simplifies the code gen”

I see. So having to inject extra CPU instructions at each call site to ensure that the stack is aligned properly is simpler!? You could argue that the compiler’s code generator has to keep track of the stack depth and offsets anyway, so this is minimal extra overhead. But that’s my point, why burden every function with this level of housekeeping when it is not necessary for the current function to operate correctly?

“Maybe it was because the Mac OS X initially targeted the PowerPC?”

When Mac OS X was first introduced, the whole Macintosh line of computers had already transitioned from the Motorola 680xx line of CPUs to the PowerPC RISC CPU. When Apple decided to completely switch all its hardware over to the Intel x86 and x86-64 architectures, it is possible (and unless I can find information to the contrary) and indeed probable, that the insular nature of the Apple culture directly lead to a vast misunderstanding of this aspect of the 32bit x86 architecture. Failure to actually look at other very successful Intel x86 operating systems and architectures, such as, oh.. I don’t know…  Windows and Linux?

I guess the frustrating thing about all this is that 32bit x86 code generated for the Mac will have extra overhead that is clearly not necessary or even desired for other platforms, such as Windows or Linux. This is like requiring all my neighbors to keep my house clean. Sure, if your compiler is going to do some kind of global or profile guided optimization, you may want to do more stack manipulations through out the application. But that is a highly specialized and rare case, and AFAIK, the tools on the platform don’t do anything like that (GCC, ObjectiveC).

When we first found out about this requirement among the dearth of documentation on these low-level details (I’m sorry, but Apple’s overall OS documentation pales in comparison to Windows’ or even Linux’s. Mac fans, flame on ;-), I posed a question to Stack Overflow figuring that since there is such a wide range of experts out there, that surely a clearly satisfactory explanation would be available in short order. I was wrong. That question has been up there for over 9 months and I still get up-votes periodically.

Even though there is one answer I selected, it doesn’t seem that the Mac ABI even adheres to the Intel doc! "It is important to ensure that the stack frame is aligned to a 16-byte boundary upon function entry to keep local __m128 data, parameters, and XMM register spill locations aligned throughout a function invocation." It says, “upon function entry” yet this isn’t the case. The Mac ABI requires the alignment to be aligned at the call site, and not on function entry! Remember that the CALL instruction will automatically push the return address onto the stack, which for x86-32 is a 32bit (DWORD) sized. Why isn’t the stack merely prepared to be aligned at the call site so that when the return address is pushed, the stack is now aligned. This would mean that ESP would be $xxxxxxx4 at the call site and $xxxxxxx0 upon entry. It is also possible interpret this statement that the function prologue code is what is responsible for doing this alignment, and not necessarily the caller. This would clearly jive with the title of this post.

So there you have, a long rambling diatribe. Why does this even matter if the compiler just handles it? Because we’re having to go through all our optimized, hand coded assembly code and make sure it keeps the stack properly aligned. It also means that for all our customers out there that also like to dabble in hand coding assembler will need to now take this into account. This coupled with the re-emergence of Position Independent Code (PIC), we’re having a jolly old time… Let the ensuing discussion begin… I’m really interested in knowing the actual reasons for this requirement… I mean could the really smart OS and Tools folks at Apple gotten this all wrong? I really have a hard time believing that because you’d think that someone would have caught it. Yet, seemingly obvious software bugs sneak out all the time (yeah, yeah, we’re just as guilty here, you got me on that one!).

Pre-emptive snarky comment: Well, if you had a compiler that did better optimizations you wouldn’t have these problems! Thank you, Captain Oblivious! Our code generator is a trade-off between decent optimizations and very fast codegen. We only do the biggest-bang-for-the-buck optimizations. We’ve even added some optimizations in recent history, like function inlining.

*ABI – Application Binary Interface. This is different from an API (Application Programming Interface), which only defines the programming model of a group of provided functions. An ABI defines the raw mechanics of how an API is implemented. An API may define a calling convention that is used, whereas the ABI defines exactly how that convention is to actually work. This includes things like how and where are the parameters actually passed to the function. It also defines which CPU registers must be preserved, which ones are considered “working” registers and can be overwritten, and so on.

Thursday, October 8, 2009

Delphi check-in log entries of the day:

25232 trunk/com/ scanner.c Thu Oct 8 20:41:10 2009 UTC ytagawa

Log:

[dcc64]
(scanner.c) Don't define ASSEMBLER for x64 for awhile.



25224 trunk/com/ codegen.c Thu Oct 8 12:35:00 2009 UTC eboling

Log:

Refactoring in PassParams to support changes to stack alignment code.
Changed the logic for aligning the stack for parameter lists for the Mac.


I’ll just leave that little tidbit for you all to chew on for a now. I’ve seen a lot of rampant speculation and and angst surrounding the release of the current roadmap. Maybe this will at least demonstrate that, yes, things are moving forward and people are actually working on interesting things.


DISCLAIMER: If you read into this more that what is actually in this post and begin ranting an raving about how this or that thing should be done one way or another, I may simply delete your comment. Remember there are no promises or anything of any value in this post. If you make a business decision based any information contained herein, then I’d really like to play you in a round of Texas Hold’em… you’d be easy prey and I’ll be happy to take all your money, and I’m not even that good.

Friday, September 4, 2009

What happened to version 13?

During the RAD Studio 2010 field test and now out in the Delphi non-tech newsgroups, there had been a lot of discussion, speculation and even some angst about the mysterious lack of version 13. Chill folks. The story is simple with no real conspiracies involved. In fact, the only conspiracy involved was that we knew from the outset that it would spark discussion and conspiracies.

After each product release there is a period of time where the internal developer builds overlap with the released product and the next release. This can cause confusion among the team and phantom errors if a developer build were to ever meet up with a released build. To limit this overlap, we try and bump the version number as early in the next release cycle as possible. The scene went like this:

Rewind to September 24th of 2008. I’m sitting at my desk reading emails, writing emails, surfing the interwebs, waiting for a build to complete, etc… There’s a knock on the door frame of my office (my door is always open). I turn around and Dave Wilhelm is standing there.

“I’m about ready bump the version number.”

“So the next version would be, uh, 13, right?”, I said with a pondering look.

“Yep. And, yes, that’s an interesting number”, Dave said with a wry smirk. A mischievous smile appeared on my face. Dave chuckled. Then he added, “I think we have two choices here. We can defiantly embrace it, or just skip it. What does our release schedule look like next year?”

“Why?”

“If we were to release in October, having a version 13 would be clearly embracing that whole mystique. You know, Halloween, black cats, zombies, ghouls, yadda yadda…”

I chuckled. “That could be a whole sub theme of the release! However, it looks like we’re slated to release about the same time next year. So that won’t work. We should just skip it. I don’t think there is a Friday the 13th around that time either.”

“I’ll ask a few folks on the team if they have any strong opinions one way or another.”

“Yep. Just like many buildings don’t have a floor 13 and go from floor 12 to 14. It will also be a fun trivia question down the road. Besides, I can see the community going into wild, random speculation and conspiracies as to why did they skip 13.”, I said with a slight smirk and a muted chuckle.

“Exactly. I also understand it is mostly a western superstition. It will certainly be fun to watch all the newsgroups get spun up.”

“Well, we live in the west. We are the ones checking in the changes. So I guess we get to decide.”, I commented defiantly.

“Yep. I’ll check with a few folks and get back to you.”, Dave said as he walked off.

About an hour later, there was another knock on my door. Dave was back.

“The comments among the team ranged from, ‘I don’t care one way or another’ to ‘Sure, go ahead and skip 13’”

“Then it’s decided. Bump it to 14, and check it in. Let the wild, random speculation begin. Explaining this conversation in a blog post will also be fun.”

We both let out a slight chortle and then proceeded to get on with our day.

There you have it. It was a largely unilateral decision. Nothing was ever mentioned about it until fairly deep into the field-test cycle and now after the release it seems to have gotten a decent amount of attention. Psych!

Thursday, September 3, 2009

Class Constructors. Popping the hood.

My last post introduced class constructors and destructors, a new language feature in Delphi 2010. I mainly covered what they were and what kinds of things they’re good for. In this post I’ll cover some of how they’re implemented. I’m sure the question on everyone’s mind is when and how they’re invoked? If you were patient enough to read my entire post, I provided a hint as to the inner workings. The rule for when they run is simple:

    • All eligible class constructors and class destructors are invoked in sequence with unit initialization and finalization, respectively.
    • If a given class constructor or destructor is eligible to be invoked (ie. it was linked into your application), it will run immediately before the initialization section for the unit in which the class is implemented. The class destructors will be invoked immediately after the finalization section for the unit in which the class is implemented.
    • Class constructors in a given unit are generally invoked in the same order of declaration, except in cases described below. Class destructors are invoked in reverse order from the class constructors.
    • For an ancestor class declared in the same unit, its class constructor will be invoked before the descendant class constructor and the class destructor is invoked after the descendant class destructor.
    • If the implementation of given class constructor references another class in the same unit with a class constructor, the referenced class’ class constructor will be invoked before the current class’ class constructor. If the references are cyclic (ie. they reference each other in their class constructors), then they are invoked in reverse order of declaration. This means that there can be cases where a class constructor can reference an “unconstructed” class.
    • Ancestor classes from external units used in the interface section are guaranteed to already have their class constructors run prior to any class constructors on descendant classes within the current unit.
    • Unit cycles can break down the deterministic nature of the above rules in the same manner as unit initialization and finalization. However, for a given unit, it is guaranteed that all the class constructors declared within in it will have already run immediately before the initialization section runs. Congruent to this rule is that it is guaranteed that all the class destructors will run immediately after the finalization section.
    • Dynamically loaded packages, using LoadPackage. Because there is no way to know exactly which classes are going to be used, just like there is no way to know which units are going to be used, all class constructors and destructors along with all unit initialization and finalizations are invoked according to the above rules.

Other rules about their use are:

    • You do not have to declare a class destructor if you declare a class constructor, and vice versa.
    • They cannot be virtual, dynamic or message.
    • They cannot be explicitly called.
    • They cannot have any parameters.
    • They do not have to be called Create and Destroy. (ie. Init and Fini are equally valid names).

With this implementation, it was easier to leverage the same table that the compiler creates for unit initialization and finalization. It satisfies this requirement: “Called automatically to initialize the class before the first instance is created or any static members are referenced.” Issues with cycles are also clearly warned against in VB.NET and C#: “Avoid circular references in Shared … since it is generally impossible to determine the order in which classes containing such references are loaded.”

Another benefit is that since it is running during the initialization/finalization phases, any threading implications are no different than the existing rules regarding unit initialization and finalization.

Class (, Static, or Shared) Constructors (and Destructors)

In my last post, I hinted at a new native Delphi language feature, class constructors and destructors. For those familiar with, say, C# or VB.NET, they are called a ‘static’ constructor (C#), or a ‘shared’ constructor (VB.NET). Let’s now take a closer look at them in terms of how they’re useful along with a little hint at how they’re implemented. Class constructors had been available in Delphi Prism, but until Delphi 2010, they were notably absent from native Delphi. The main reason for this was that the .NET runtime controlled and defined when a ‘static’ or ‘shared’ constructor was invoked. In native Delphi there was no defined mechanism to do the same.

From the C# documentation:

Called automatically to initialize the class before the first instance is created or any static members are referenced. The constructor cannot be called directly.

From the VB.NET documentation:

Shared constructors initialize a type's shared variables; they are run after the program begins executing, but before any references to a member of the type. A shared constructor specifies the Shared modifier, unless it is in a standard module in which case the Shared modifier is implied.

Since the .NET runtime is a garbage-collected environment, there are no references or mention of ‘class destructors’. Because native Delphi is is not garbage collected and requires explicit destruction of instances and freeing of memory, it stood to reason that for congruency, native Delphi would also have the notion of a class destructor.

First of all let’s look at the syntax:

type
EDliException = class(Exception)
private
class constructor Create;
class destructor Destroy;
end;


 


Technically, it does not matter where in the class declaration they are declared (private, public, protected, published) since, as the  documentation above states, “The constructor [destructor (added)] cannot be called directly.” So in this example, I just made them private to merely make it more clear in the source that they cannot be called. Just like the other kinds of ‘class’ methods, the body of theses methods can only access other class methods or variables. They also have no implicit “Self”, so you cannot call virtual class methods in a polymorphic manner. You can have one and only one class constructor/destructor per class type. As we’ll see in a moment, you should treat the class constructor/destructor methods in a manner similar to a unit’s initialization/finalization section. That’s it. It’s pretty simple, really.


Now let’s look at why these are useful. There were several main reasons for adding this to the language. They were:



  1. Improved encapsulation

  2. Better control over smart-linking

  3. Better language compatibility with Delphi-Prism

Improved encapsulation


How many times have you needed to initialize something related to a specific class? What if your class is using the singleton pattern and you need to create that single instance? How about registering the class with a “class-factory?” Prior to Delphi 2010, there were several options available to you, none of which were really in keeping with the OOP notion of encapsulation. You could put all the code into the initialization section of the unit in which the class lived, add a regular class method and call it explicitly, or manually integrate the init code into your application’s startup. By moving all this code into a class constructor, the mere act of “touching” the class will cause the class constructor to run in keeping with the above rules.


Better control over smart-linking


Loosely coupled with improved encapsulation is the notion that by moving any initialization code into the class constructor you have a little more control over what code is linked into your application. You can now take advantage of the fact that as long as the class type isn’t referenced referenced anywhere in your code, none of the code related to the class type is linked in, including the VMT, virtual methods, RTTI, etc.. If you had placed this init code into the initialization section of its containing unit, then at least the VMT, virtual methods and RTTI would have been linked into your application. Even though none of your code references it. The new enhanced RTTI throws an interesting wrinkle to this theory, but that will have to be covered later.


Better language compatibility with Delphi Prism


As Delphi Prism gains popularity, more people will need to maintain some of their code in a manner that they can compile with either compiler. There are still many language constructors that both compilers have that the other doesn’t, but this is a continuing effort to close that gap where it makes sense. Expect to see more work in this area, in both compilers.


In my next post, we’ll “pop the hood” (or bonnet, for our good friends across the pond) and take a peek at how they work and exactly when they are invoked. I will say that many people tend to read way, way too much into this simple statement describing when a class constructor is invoked; “Called automatically to initialize the class before the first instance is created or any static members are referenced.” The only temporal reference in that statement is “…before…”. I will leave you to consider the implications of that word, lest many of you begin to talk about “threading issues” and “code-bloat.” Class constructors and destructors are to classes as initialization and finalization are to units.

Saturday, August 29, 2009

Exceptional Procrastination

I kept putting this post off… ok, ok… that was a really bad pun…

Seems there was a little bit of concern about my last post regarding the new ‘delayed’ directive. Christian Wimmer had a few critiques regarding the implementation and how the exception that was raised was an EExternalException with an obscure exception code. There is a simple explanation for this. The delay load helper functions were taken directly from the C++Builder RTL. By that I mean, the delayhlp.c file gets built to a .obj file by the C++ compiler and then directly linked into the Delphi System unit. There were several key reasons for this. The first of which was the code was already written, has been in many versions of C++Builder RTL (including back in the old Borland C++ days) and has been extensively tested. Another reason is that in order for Delphi and C++Builder to “play-nice,” when a Delphi unit is linked in C++Builder that contains a reference to a delay load import, ILink32 takes over the duties of generating the proper delay load functionality into the PE file. So the C++RTL version of delayhlp.c is what is used. In order to things to remain consistent, this is the route taken. Had there been two delay-load helper functions in the case of a C++Builder application, then any existing C++ code that used the delay load hooks would only work on other C++ code and vice-versa.

Fear not, all is not lost. To satisfy our good friend, Christian’s request, here is a unit that you can use to generate nice, unique Delphi specific exceptions. This is accomplished by leveraging the ability for the delayhlp.c code to be “hooked.” This code also demonstrates another new Delphi language feature, class constructors and destructors. I will describe them in better detail in a subsequent post. If you never reference any of the declared exception types in this unit, the hook is not installed and the normal EExternalException is raised. Presumably you would use this unit for the purpose of actually catching the exceptions and doing something interesting with them. Another thing to note is that you should also be able to add this unit to a C++Builder application and it work for any delay-load functions done in the existing way for C++ and any Delphi units that reference Delphi imports with the delayed directive.

unit DelayExcept;

interface

uses SysUtils;

type
EDliException = class(Exception)
private
class constructor Create;
class destructor Destroy;
end;

EDliLoadLibraryExeception = class(EDliException)
private
FDllName: string;
public
constructor Create(const ADllName: string); overload;

property DllName: string read FDllName;
end;

EDliGetProcAddressException = class(EDliException)
private
FDllName: string;
FExportName: string;
public
constructor Create(const ADllName, AExportName: string); overload;
constructor Create(const ADllName: string; AOrdinal: LongWord); overload;

property DllName: string read FDllName;
property ExportName: string read FExportName;
end;

implementation

{ EDliLoadLibraryExeception }

constructor EDliLoadLibraryExeception.Create(const ADllName: string);
begin
inherited Create(Format('Unable to load ''%s''', [ADllName]));
FDllName := ADllName;
end;

{ EDliGetProcAddressException }

constructor EDliGetProcAddressException.Create(const ADllName, AExportName: string);
begin
inherited Create(Format('Unable to locate export name ''%s'' in ''%s''', [AExportName, ADllName]));
FDllName := ADllName;
FExportName := AExportName;
end;

constructor EDliGetProcAddressException.Create(const ADllName: string;
AOrdinal: LongWord);
begin
inherited Create(Format('Unable to locate export ordinal ''%d'' in ''%s''', [AOrdinal, ADllName]));
FDllName := ADllName;
FExportName := IntToStr(AOrdinal);
end;

function DelayLoadFailureHook(dliNotify: dliNotification; pdli: PDelayLoadInfo): Pointer; stdcall;
begin
Result := nil;
if dliNotify = dliFailLoadLibrary then
raise EDliLoadLibraryExeception.Create(pdli.szDll);
if dliNotify = dliFailGetProcAddress then
if pdli.dlp.fImportByName then
raise EDliGetProcAddressException.Create(pdli.szDll, pdli.dlp.szProcName)
else
raise EDliGetProcAddressException.Create(pdli.szDll, pdli.dlp.dwOrdinal);
end;

{ EDliException }

class constructor EDliException.Create;
begin
SetDliFailureHook(DelayLoadFailureHook);
end;

class destructor EDliException.Destroy;
begin
SetDliFailureHook(nil);
end;

end.

Tuesday, August 25, 2009

Procrastinators Unite… Eventually!

We’re all taught at an early age to “Never put off until tomorrow that which can be done today.” In general, that is wise advice. However there are some cases where you do want to wait until the last possible moment to do (or not do) something. In fact, that is one of the overall tenets of  Agile Programming; delay decisions until the last possible moment because you always know more about a problem tomorrow than you do today and can make a better, more informed decision. But, I digress. I’m not here to talk about philosophies of life, or to introduce another “agile methodology” or even about a new weight loss plan based on bacon, lard and cheese puffs.

How many of you have written this same bit of boilerplate code or something similar over and over again?


if OSVersion >= 5.0 then
begin
Module = LoadLibrary('kernel32.dll');
if Module <> 0 then
begin
Proc := GetProcAddress(Module, 'APICall');
if Assigned(Proc) then
Proc(Param1, Param2);
end;
end else
{ gracefully fallback }

 


What if you could just do this?


if OSVersion >= 5.0 then
APICall(Param1, Param2);
else
{ gracefully fallback }

 


The astute among you would immediately see that with previous Delphi releases, the second form, while certainly preferable, at some point the call to “APICall” would eventually have to effectively go through some bit of code similar to the first bit of code. Normally, you would declare an external API reference like this:


procedure APICall(Param1, Param2: Integer); stdcall; external 'kernel32.dll' name 'APICall';

That will cause the linker to emit a external reference into the executable binary that is resolved at load time. Therein lies the problem. That is the situation that the first bit of code above was designed to avoid. If APICall didn’t existing in ‘kernel32.dll’ at load time, the whole application would fail to load. Game over. Thanks for playing. Now, what if you could write code similar the second block of code above and still declare your external API calls in a manner similar to above?


Starting with Delphi 2010, you can do exactly the scenario I describe. To make the second code block work even if “APICall” isn’t available on the version of the OS on which your application is currently running, we’ve introduced a new directive to be used only in the above context, delayed;

procedure APICall(Param1, Param2: Integer); stdcall; external 'kernel32.dll' name 'APICall' delayed;


Simply put, by adding the delayed directive, that instructs the linker to generate the external API reference differently in the executable binary. Now Delphi’s RTL will take care of all that ugly “late-binding” boilerplate code for you. Rather than generating the import in the normal “Imports” section of the executable’s PE file, it is generated into the “Delayed Imports” section following the published PE spec. This also requires that the RTL now has a generic function that does the proper lookups and binds the API whenever it is called the first time. Subsequent calls are just as fast as a normal import.


This is different than similar functionality available in ILink32 from C++Builder wherein you can only specify an entire dll in which all references are delay loaded. Also, in C++ you cannot specify kernel32.dll or even ntdll.dll to be delay loaded, since the very startup of any application or dll requires them to already be loaded. In Delphi you can, since it is on an API-by-API basis. The intent of this feature was to make managing all the new APIs from Windows Vista and now Windows 7 much easier without having to continuously and manually write all the delay loaded boilerplate code. Throughout VCL, we can simply make runtime decisions on which APIs to call without always going through those manually coded “thunks.” They are now simply handled by the compiler/linker and the source code barely reveals the fact that something is late-bound.


In a future release, we are considering adding both the API-by-API capability to C++Builder and a way to specify an entire dll to be late-bound in Delphi.

Friday, August 21, 2009

The “Nitty Gritty” details on Casting an Interface Reference in Delphi 2010

Malcolm Groves let loose on a new Delphi compiler feature where you can now cast an interface reference to the implementing Delphi class. Joe White was interested in the “gritty” details about how this was implemented. It turns out that it was deceptively easy once I figured out the internal compiler logic for handling “is” tests and “as” and hard casts. All three cases use the same internal mechanism implemented in the Delphi RTL.

Because all Delphi interfaces have three core methods, QueryInterface, _AddRef, and _Release, you know that you can always call QueryInterface on any interface reference. QueryInterface is declared thusly:

function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;

The last parameter is an “untyped out” parameter meaning that it will accept a reference to any variable of any type. What if you called QueryInterface with a special GUID (remember, GUID = Globally Unique IDentifier) and instead of assigning an interface reference to the Obj parameter, the implementing class instance was assigned instead? The base implementation of QueryInterface simply calls TObject.GetInterface. It is in that method that code will now look for this special GUID (which is declared in the implementation section of System.pas) and assign Obj the object reference instead of a new interface reference.

Granted, this technique does have a couple of potential issues. If, for some reason, the user decides to manually implement QueryInterface and never calls TObject.GetInterface, then none of the above casting and “is” testing will work. It will behave as if the implementing class was not implemented in Delphi. Another caveat, is if you’re doing cross-process marshaling of interfaces where both sides are Delphi 2010, you should not attempt to use this technique. In fact, if you’re doing any kinds of traditional COM programming, using this feature can yield strange results. This feature was a direct result of many requests from customers who are using interfaces for purposes outside COM.

Thursday, August 20, 2009

A Tempest in a Teapot or something more sinister?

If you’re a well connected internet maven who also happens to be a Delphi user, you’re probably no doubt aware of some of the recent reports about a new virus/trojan threat that hits pretty close to home. There are many reports among the mainstream internet press that are discussing the emergence of a virus affectionately known as the “Compile-a-virus” or by the more mundane and sanitary name, W32/Induc-A. It seems that this particular virus is targeting older versions of Delphi (specifically Delphi 4-7) and replicates itself by rebuilding a new version of SysConst.dcu and placing in back in your <root>\Lib folder. Ironically, it doesn’t simply overwrite the existing SysConst.dcu without first backing up the original, called SysConst.bak. It does use the existence of this .bak file as a signal that it’s already done its job and it should just leave that installation alone. Because it doesn’t actually delete anything, it is a gentleman among viruses ;-). Once Delphi is infected, every executable and dll that is built which links in the code in SysConst.dcu will now carry the virus which when run will seek out any Delphi installation and the process repeats.

Aside from the pure mechanics of how this thing works, there are also a lot of response among the community and press from “OMG, the sky is falling” to “nothing to see here, move along.” Fear mongering is just as bad of a response as ignoring the problem. At this point, here at Embarcadero, we’re actively analyzing situation and overall impact to our community. We’re also working on recommendations about how to find out if you’re infected and what to do once you see that you are. Throughout all this we’re working on recommended steps can you take to guard against re-infections. Rest assured that we’re neither ignoring this threat, nor are we going to do anything to blow it out of proportion. All signs indicate this is a serious and credible threat and users should remain diligent in ensuring that they either install or update their virus scanners. Many of the popular freely available scanners are now able to detect this threat, both in compiled binaries and are able to detect an infected SysConst.dcu.

As we get more information and have more recommendations, we’ll make it available. Moving forward we’re brainstorming about possible solutions that you, the customer, can use to be not only guard against future similar threats, but also if a new threat were found there can be a prescribed mechanism to detect and correct the problem.