See some historical notes on the hardware concept of address.

Other notes on pointers and control blocks:

Contrasting Object References with Capabilities
Nodes as Control Blocks
The control block was introduced only after the index register was introduced but this is a historical accident as far as I can see. The index register (later the general register) largely eliminated the need for self modifying programs. Another still later hardware feature was the memory map. Early maps provided separate code sections and data sections, reminiscent of Harvard architectures. The rationale for this particular division was that the same code was often needed for several different pieces of data. In a timesharing system the code of the interactive text editor was large enough so that one attempted to avoid duplicating it for each current user of that function. Even in systems that were unlikely to have more than one user of the editor in core at once could benefit by not having to swap the editor code proper in and out with the individual’s particular editing state. In hindsight this was a combination of state and behavior—an object.

When this pattern was applied to very small objects, the code could be compiled with fixed virtual addresses into the data segment. The context of the code was determined by the current map. Indeed the map supplanted the role of the register in defining the instance at hand. Alas this trend gets us back to wanting large addresses in the instruction stream. I think now that this is a bad idea and that current processors are moving in the right direction. In an environment where all addresses are deemed to be 64 bits, is awkward to compile C code for:

extern int x;
void xx(void){x = 0;}
On the 64 bit SPARC I get
xx:
        sethi   %hh(x), %o1
        sethi   %lm(x), %g5
        or      %o1, %hm(x), %g1
        sllx    %g1, 32, %g4
        add     %g4, %g5, %g1
        retl
        st      %g0, [%g1+%lo(x)]
Forty years later, I finally agree that addresses do not belong in the instruction stream. (Incidental note: IBM’s 64 bit version of the 360 architecture finally ameliorates the problem of code pointing to code. In the original 360, conditional branches could span only 4K from some general register. Compilers (and humans) had a terrible time maintaining registers to access code in a routine larger than 4KB.)

Keykos and Large Addresses

The Keykos Segment Architecture takes pains to make it easy to share portions of RAM by direct mapping. This support was unconventional in that the user (or user’s agent) chose the address in his space where the shared data would be mapped. This was unconventional since most kernels presume that the address space of the user belongs to the kernel and is to doled out at the discretion of the kernel. Keykos delivers this feature to the PL/I programmer via the EXTERNAL language feature. The address of a PL/I variable declared EXTERNAL was presumed by the compiler to be provided at load time. The Keykos loader would choose an address range for the variable suitable for the variable and the Keykos segment mapping rules. Capability addressing language primitives were provided so that the PL/I program which held a segment capability, could cause that segment to appear as the contents of the external variable, providing the PL/I program with efficient and native read-write access to the segment.

The programmer had to choose one of three powers of 16 as the size of his external variable and the unused part of that address range could not be used for other purposes. This was a trade-off between efficiency and economy of address space. The resulting economies transcend several abstraction levels from involved nodes thru hardware mapping tables and caches. For situations where better economy of virtual addresses was required more complex library routines could provide more flexible mapping. We did not find such a need. In summary Keykos enjoys large virtual address spaces even as it limits the demand for them by segmenting large complex applications into many spaces.

Another pattern which I think was not used in Keykos was its ability for hierarchical sharing. Such an application might be where one program would produce a segment each of whose pages was the most recent weather prediction for some particular city. The entire segment would be shared among several users of the data. This requires two levels of assembly of segments into larger segments. The hardware does this well, but few if any kernels export this hardware ability.