The Von Neumann architecture is defined by the fact that both the machine instructions and data are stored in the same memory space. This fact necessitates dividing memory into text and data segments.
In modern operating systems, there are more than just these two segments. Most systems use a single text segment, but actually use up to three data segments, depending on the storage class of the data being stored there. The four segments can be described as follows:
+---+ | 5 | | 4 | <- sp | 3 | | 2 | | 1 | +---+
The size of the text and data segments are known as soon as compilation or assembly is completed. The stack and heap segments, on the other hand, grow and shrink during program execution. For this reason, they tend to be configured such that they grow toward each other. This way, they each have a fixed starting point (one adjacent to the text and data segments, and the other at one end of the entire memory space), and the boundary between them is flexible. Both can grow until all available memory is used.
+-----------+ | | | text | (fixed size) | | +-----------+ | | | data | (fixed size) | | +-----------+ | stack | | growth +-----------+ V | | | free | | | +-----------+ ^ | heap | | growth +-----------+
We can have as many .text and .data blocks in the source code as we want. The assembler will consolidate all the .text blocks into the text segment, and and all the .data blocks into the data segment.
Each subprogram in a MAL program should have its own .text block and its own .data block.
# Subprogram 1 .data # Variables for subprogram 1 .text # Subprogram body ret # Subprogram 2 .data # Variables for subprogram 2 .text # Subprogram body ret # Main program .data # Variables for main .text # Main body ret
Why use multiple .text and .data sections in a program?
Variables should be defined along with the subprogram that uses them, for the sake of readability.
In the assembler's point of view, all variables are global. The notion of a variable's scope in C or Java is enforced by the compiler, not the hardware. Hardware knows only about memory addresses, and the compiler must keep track of which addresses are used by each subprogram.
In assembly language, it is the programmer's responsibility to ensure that each subprogram accesses only its own variables. Although the assembler will not prevent it, you must ensure that no subprogram accesses variables of another subprogram. If you do, your program is not modular, and your subprograms are not independent, portable modules as they should be.
A subprogram should never be considered part of the larger program it is used in. It should be considered an independent module that can be used within any other program without modification.
As discussed in Chapter 7, Code Quality Standards, all variable names in assembly language programs should be prefixed with the name of the subprogram they belong to.