So, the "* = * + N" technique of grabbing memory leaves the minutiae of managing the actual addresses to the assembler, rather than the developer.
This is clearly most common for simple variables (1 byte, 2 bytes) rather than larger spaces, but the concept is sound. You want to have larger areas for things like terminal buffers, or disk buffers, etc.
Now, instead of statically allocating these areas within the assembly program directly, you can "dynamically" allocate them at runtime. Here, you need to simply know where your "free memory" begins. And from there, you program can gobble blocks as necessary.
Early UCSD Pascal has the simple concept of "mark" and "release". Here, it maintained a pointed to the start of the free area. When you wanted more memory, you grabbed a copy, and then bumped it up. When you were done, you simply reset the pointer back.
So:
Code: Select all
ptr = mark(1024);
... work with ptr ...
release(prr);
But in all of these cases, after the code is built, and at runtime, is when these addresses are decided. They're not "assigned" by the developer (i.e. I/O buffer is going to be page $0200). Rather, they're just organically scattered through the code and free memory space and referenced symbolically.
Sometime you do care exactly where a block of memory should be, but many times, you don't. You just need to know you have 64 bytes open someplace safe.