Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2012-02

System/370 port. Episode 5 - Addressing data

2 messages · 2 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

steve smithers

Episode 5 - Addressing data

This is where I really expose my ignorance of FreePascal internals. I know a teeny little bit about Delphi so I hope it carries through.

As far as 370 Assembler is concerned, and this probably applies to most assemblers, there is no inherent difference between data and code, it is just a label defined as an aide-memoire. There is no reason, for example, why you can't load an instruction, or part of it, into a register, modify it and store it back into the program. I have even seen some programs that pull off such tricks intentionally. I, personally, think shooting is too good for programmers who get up to these sorts of stunts, but it happens. Conversely, there is no reason, as far as the processor is concerned, why you cannot branch (370 for Jump) into the middle of a character array for example. All assembler programmers have come across this one too, it's called a bug.

So ultimately, it doesn't matter whether we are generating code for a branch instruction or for a move instruction or anything else we use the same basic idea using index registers that we have discussed previously. However, it won't surprise you to learn that there are some complications.

Not all instructions support index registers. But remember that the address A for an label is given by A := B + D + I where B is the value held in the base register, D is the displacement held in the instruction and I is the value in the Index register. This sum is performed by the processor internally.  So, using the example we had previously:
        LA    R1,(LABELB-PROG)/4096
        SLL   R1,12
        B     LABELA-((LABELA-PROG)/4096)*4096(R1) Let's assume that the A (Add) instruction doesn't support index registers, we can rewrite the code fragment as:
        LA    R1,(LABELB-PROG)/4096
        SLL   R1,12
        LA    R1,LABELA-((LABELA-PROG)/4096)*4096(R1)         A     R1,0(R1)
The final LA puts the address A in register 1 by doing the arithmetic above, and the A (Add) now specifies a displacement of 0 from base register R1. (we wouldn't actually do it this way under these circumstances. This is an artificial example for illustrative purposes only before any assembler programmers write in)

Right - FreePascal - I'm out on a limb here but... All variables (or constants or labels for that matter) have to be defined before use to Pascal (See Note 1 at bottom). At the time they are defined, an entry will be built in a symbol table. Now the symbol table has to point at the storage reserved for the variable; There are only a limited number of ways it could do that.

1) It could hold the absolute address. That's stupid because it means the program has to be loaded at the same place all the time.

2) It could hold the address of the variable as a relocatable value whose value is resolved, either at link-edit time or at program-load time. That doesn't really help us when we come to accessing dynamic storage or using shared code. So...

3) So it's my guess that it holds the address as a pointer to a block of storage allocated on the heap or the stack or wherever else it wants to put it. and an offset into that block. (plus other stuff like length and type) Sound familiar? This is base / displacement addressing!  It's just that the displacement isn't limited to 4k and the base isn't in a register.

Or maybe I'm wrong. But I don't think I am. Now the displacement, sorry offset, won't have the same limitations that 370 code has, but I've already demonstrated a way to handle this. The only realistic example I can think of that runs counter to this, is where values are themselves in registers. Then, it's not a storage reference problem.

Note 1. This isn't strictly true I suppose. You can do something like With TObject.Create
begin
....
end;
However, the compiler has to create a temporary variable to store this value in order to access the object, otherwise it's just memory floating around. At least I think it does!

Regards Steve

Reply by email

Sven Barth
to steve smithers
steve smithers wrote 19 lines
Right - FreePascal - I'm out on a limb here but... All variables (or constants or labels for that matter) have to be defined before use to Pascal (See Note 1 at bottom). At the time they are defined, an entry will be built in a symbol table. Now the symbol table has to point at the storage reserved for the variable; There are only a limited number of ways it could do that. 1) It could hold the absolute address. That's stupid because it means the program has to be loaded at the same place all the time. 2) It could hold the address of the variable as a relocatable value whose value is resolved, either at link-edit time or at program-load time. That doesn't really help us when we come to accessing dynamic storage or using shared code. So... 3) So it's my guess that it holds the address as a pointer to a block of storage allocated on the heap or the stack or wherever else it wants to put it. and an offset into that block. (plus other stuff like length and type) Sound familiar? This is base / displacement addressing! It's just that the displacement isn't limited to 4k and the base isn't in a register.

There are basically two locations where a variable can reside:
* on the stack
* on the heap

If the variable is located on the stack then it is normally addressed using an addressing relative to the stack pointer or the stack base (ESP and EBP on x86).

If the variable is located on the heap there can be two possibilities why it resides there:
* it's a global variable, thus the compiler reserves some space for the variable in the section of the executable (however that is done in the specific binary format). When the executable is loaded by the OS it loads the section with all the variables into memory and the runtime code can then access them. The memory address the compiler uses depends on the target system. On Windows all variable (and function) addresses are relative to the base address (which can be changed using a compiler parameter). This is basically your (1). Windows supports also relocatable images, but this works by having the OS change all absolute addresses to their new values when loading (yes, Windows does that). On Linux there is the concept of Position Independant Executables (PIE) where all global variables are accessed relative to the Global Offset Table which normally always resides in a specific register (AFAIK EBX on x86). There is a non-PIE mode, too, on Linux, but I don't know currently whether the executable is really not relocateable then.
* it's a memory area that was reserved using "GetMem" or similar calls to FPC's heap manager. In that case the compiler does not need to do anything, because this is a runtime allocated memory. The pointer that points to the memory is then again either a local, stackbased variable or a global one.

Show quoted text 15 lines
Or maybe I'm wrong. But I don't think I am. Now the displacement, sorry offset, won't have the same limitations that 370 code has, but I've already demonstrated a way to handle this. The only realistic example I can think of that runs counter to this, is where values are themselves in registers. Then, it's not a storage reference problem. Note 1. This isn't strictly true I suppose. You can do something like With TObject.Create begin .... end; However, the compiler has to create a temporary variable to store this value in order to access the object, otherwise it's just memory floating around. At least I think it does!

Yes, the compiler creates a temporary here.

Regards,
Sven

Reply by email