|
As you've seen, the 80x86 CPU doesn't deal with variables that have names like I, Profits, and LineCnt. The CPU deals strictly with numeric addresses it can place on the address bus like $1234_5678, $0400_1000, and $8000_CC00. HLA, on the other hand, does not force you refer to variable objects by their addresses (which is nice, because names are so much easier to remember). This abstraction (allowing the use of names rather than numeric addresses in your programs) is nice, but it does obscure what is really going on. In this section, we'll take a look at how HLA associates numeric addresses with your variables so you'll understand (and appreciate) the process that is taking place behind your back.
Take another look at Figure 3-7. As you can see, the various memory sections tend to be adjacent to one another. Therefore, if the size of one memory section changes, then this affects the starting address of all the following sections in memory. For example, if you add a few additional machine instructions to your program and increase the size of the code section, this may affect the starting address of the static section in memory, thus changing the addresses of all your static variables.[10] Keeping track of variables by their numeric address (rather than by their names) is difficult enough; imagine how much worse it would be if the addresses were constantly shifting around as you add and remove machine instructions in your program! Fortunately, you don't have to keep track of all of this, HLA does that bookkeeping for you.
HLA associates a current location counter with each of the three static declaration sections (static, readonly, and storage). These location counters initially contain zero and whenever you declare a variable in one of the static sections, HLA associates the current value of that section's location counter with the variable; HLA also bumps up the value of that location counter by the size of the object you're declaring. As an example, assume that the following is the only static declaration section in a program:
static b :byte; // Location counter = 0, size = 1 w :word; // Location counter = 1, size = 2 d :dword; // Location counter = 3, size = 4 q :qword; // Location counter = 7, size = 8 l :lword; // Location counter = 15, size = 16 // Location counter is now 31.
Of course, the run-time address of each of these variables is not the value of the location counter. First of all, HLA adds in the base address of the static memory section to each of these location counter values (that we call displacements or offsets). Secondly, there may be other static objects in modules that you link with your program (e.g., from the HLA Standard Library), or even additional static sections in the same source file, and the linker has to merge the static sections together. Hence, these offsets may have very little bearing on the final address of these variables in memory. Nevertheless, one important fact remains: HLA allocates variables you declare in a single static declaration section in contiguous memory locations. That is, given the declaration above, w will immediately follow b in memory, d will immediately follow w in memory, q will immediately follow d, and so on. Generally, it's not good coding style to assume that the system allocates variables this way, but sometimes it's convenient to do so.
Note that HLA allocates memory objects you declare in readonly, static, and storage sections in completely different regions of memory. Therefore, you cannot assume that the following three memory objects appear in adjacent memory locations (indeed, they probably will not):
static b :byte; readonly w :word := $1234; storage d :dword;
In fact, HLA will not even guarantee that variables you declare in separate static (or whatever) sections are adjacent in memory, even if there is nothing between the declarations in your code (e.g., you cannot assume that b, w, and d are in adjacent memory locations in the following declarations, nor can you assume that they won't be adjacent in memory):
static b :byte; static w :word := $1234; static d :dword;
If your code requires these variables to consume adjacent memory locations, you must declare them in the same static section.
Note that HLA handles variables you declare in the var section a little differently than the variables you declare in one of the static sections. We'll discuss the allocation of offsets to var objects in the chapter on procedures.
[10]Note that the operating system typically aligns the static section on a 4,096-byte boundary, so you many need to add a sufficient number of new instructions to cause the code section to grow in size across a 4K boundary before the static addresses actually change. This isn't necessarily true for all memory sections, however.
|