Hubbry Logo
Overlay (programming)Overlay (programming)Main
Open search
Overlay (programming)
Community hub
Overlay (programming)
logo
8 pages, 0 posts
0 subscribers
Be the first to start a discussion here.
Be the first to start a discussion here.
Contribute something
Overlay (programming)
Overlay (programming)
from Wikipedia

Schematic

In a general computing sense, overlaying means "the process of transferring a block of program code or other data into main memory, replacing what is already stored".[1] Overlaying is a programming method that allows programs to be larger than the computer's main memory.[2] An embedded system would normally use overlays because of the limitation of physical memory, which is internal memory for a system-on-chip, and the lack of virtual memory facilities.

Usage

[edit]

Constructing an overlay program involves manually dividing a program into self-contained object code blocks called overlays or links, generally laid out in a tree structure.[b] Sibling segments, those at the same depth level, share the same memory, called overlay region[c] or destination region. An overlay manager, either part of the operating system or part of the overlay program, loads the required overlay from external memory into its destination region when it is needed; this may be automatic or via explicit code. Often linkers provide support for overlays.[3]

Example

[edit]

The following example shows the control statements that instruct the OS/360 Linkage Editor to link an overlay program containing a single region, indented to show structure (segment names are arbitrary):

 INCLUDE SYSLIB(MOD1)
 INCLUDE SYSLIB(MOD2)
 OVERLAY A
   INCLUDE SYSLIB(MOD3)
     OVERLAY AA
       INCLUDE SYSLIB(MOD4)
       INCLUDE SYSLIB(MOD5)
     OVERLAY AB
        INCLUDE SYSLIB(MOD6)
 OVERLAY B
    INCLUDE SYSLIB(MOD7)
                       +--------------+
                       | Root Segment |
                       | MOD1, MOD2   |
                       +--------------+
                               |
                    +----------+----------+
                    |                     |
             +-------------+       +-------------+
             |  Overlay A  |       |  Overlay B  |
             |  MOD3       |       |  MOD7       |
             +-------------+       +-------------+
                    |
           +--------+--------+
           |                 |
    +-------------+   +-------------+
    | Overlay AA  |   | Overlay AB  |
    | MOD4, MOD5  |   | MOD6        |
    +-------------+   +-------------+

These statements define a tree consisting of the permanently resident segment, called the root, and two overlays A and B which will be loaded following the end of MOD2. Overlay A itself consists of two overlay segments, AA, and AB. At execution time overlays A and B will both utilize the same memory locations; AA and AB will both utilize the same locations following the end of MOD3.

All the segments between the root and a given overlay segment are called a path.

Applications

[edit]

As of 2015, most business applications are intended to run on platforms with virtual memory[citation needed]. A developer on such a platform can design a program as if the memory constraint does not exist unless the program's working set exceeds the available physical memory. Most importantly, the architect can focus on the problem being solved without the added design difficulty of forcing the processing into steps constrained by the overlay size. Thus, the designer can use higher-level programming languages that do not allow the programmer much control over size (e.g. Java, C++, Smalltalk).

Still, overlays remain useful in embedded systems.[4] Some low-cost processors used in embedded systems do not provide a memory management unit (MMU). In addition many embedded systems are real-time systems and overlays provide more determinate response-time than paging. For example, the Space Shuttle Primary Avionics System Software (PASS) uses programmed overlays.[5]

Even on platforms with virtual memory, software components such as codecs may be decoupled to the point where they can be loaded in and out as needed.

Historical use

[edit]

IBM introduced the concept of a chain job[6] in FORTRAN II. The program had to explicitly call the CHAIN subroutine to load a new link, and the new link replaced all of the old link's storage except for the Fortran COMMON area.

IBM introduced more general overlay handling[7] in IBSYS/IBJOB, including a tree structure and automatic loading of links as part of CALL processing.

In OS/360, IBM extended the overlay facility of IBM 7090/94 IBSYS IBLDR[8] by allowing an overlay program to have independent overlay regions, each with its own overlay tree. Another dynamic system of overlays could be constructed using the LOAD or LINK system macros. Separately-compiled modules were loaded anywhere in available memory and retained until a DELETE macro was issued for them. Loaded programs could, in turn, load other programs and so on.[9] OS/360 also had a simpler overlay system for transient operating system SVC routines, using 1024-byte SVC transient areas.

Systems using Memory segmentation typically do not require overlay facilities. Programs on Burroughs Large Systems are composed of segments, which are natural divisions of the program such as COBOL paragraphs, ALGOL procedures, data structures, etc. Each segment is dynamically loaded as needed, and then possibly removed to swapped out to free storage. Specific overlay structures are not necessary because the MCP overlays automatically.[10] Multics, likewise, does not require specific overlays, because each module is a separate segment, which the supervisor loads, deletes, or swaps out as needed.

In the home computer era overlays were popular because the operating system and many of the computer systems it ran on lacked virtual memory and had very little RAM by current standards: the original IBM PC had between 16K and 64K, depending on configuration. Overlays were a popular technique in Commodore BASIC to load graphics screens.[2]

"Several PC/MS-DOS linkers in the 1980s supported [overlays] in a form nearly identical to that used 25 years earlier on mainframe computers."[4][11] Binary files containing memory overlays had de facto standard extensions .OVL[11] or .OVR[12] (but also used numerical file extensions like .000, .001, etc. for subsequent files[13]). This file type was used among others by WordStar[14] (consisting of the main executable WS.COM and the overlay modules WSMSGS.OVR, WSOVLY1.OVR, MAILMERGE.OVR and SPELSTAR.OVR, where the "fat" overlay files were even binary identical in their ports for CP/M-86 and MS-DOS[15]), dBase,[16] and the Enable DOS office automation software package from Enable Software. Borland's Turbo Pascal[17][18] and the GFA BASIC compiler were able to produce .OVL files.

See also

[edit]

Notes

[edit]

References

[edit]

Further reading

[edit]
[edit]
Revisions and contributorsEdit on WikipediaRead on Wikipedia
from Grokipedia
In programming, an overlay is a technique that enables the execution of programs larger than the available physical by dividing the application into modular segments, which are loaded sequentially into the same region, overwriting prior segments when they are no longer needed. This method reuses limited main space efficiently for different program phases, such as loading an initial module for one stage of execution before replacing it with another. Overlays were essential in environments with fixed partitioning schemes, where was statically divided into regions, and programs exceeding a partition's size could still run by swapping segments. The overlay process is typically handled manually by the or through application-level , without relying on operating system support for . Programmers structure the into a tree-like of overlays, where a root segment remains resident while child segments are brought in as required, often using stubs or loaders to manage the transitions. For instance, in a multi-phase application, the first phase might occupy memory until completion, at which point the loads the next phase from secondary storage like disk or tape, adjusting addresses to fit the . This approach minimizes internal fragmentation in fixed partitions but demands careful design to avoid conflicts between overlapping segments. Historically, overlays emerged in the era of early mainframe computers during the and , when RAM capacities were severely constrained, often measured in kilobytes, making it impractical to load entire programs at once. They provided a for running complex applications on hardware like the or systems, predating modern mechanisms introduced in the 1970s. While effective for infrequently used code modules, such as error-handling routines, overlays fell out of favor with the advent of paging and segmentation in operating systems like and UNIX, which automated . Today, overlays persist in niche embedded systems or microcontrollers with , where resources remain tight, but they are generally considered an archaic technique.

Definition and Purpose

Core Concept

In overlay programming, a technique is employed to enable programs larger than the available physical by sequentially loading distinct modules into a shared region during execution. This approach allows multiple program segments to occupy the same at different times, thereby minimizing the overall required for the program. The fundamental principle of overlays is that only the currently active module resides in , while inactive modules are stored on secondary storage and swapped in as needed, ensuring efficient utilization of limited resources without requiring the entire program to be resident simultaneously. This dynamic swapping is orchestrated to align with the program's execution flow, loading modules just before they are invoked to avoid memory exhaustion. Overlays differ from segmentation, which involves dividing into fixed, logical units for and , by emphasizing runtime replacement of segments within a designated area rather than static partitioning. Key terminology includes the root, the always-resident portion of the program that serves as the and coordinates execution; the overlay area, the region where modules are loaded and replaced; and the overlay driver, the software component responsible for managing the loading and unloading of these modules from storage.

Memory Constraints Addressed

In the era preceding widespread virtual memory systems, early computers faced severe limitations in main memory capacity, typically ranging from a few kilobytes to hundreds of kilobytes in 1960s mainframes such as the models, which offered physical core storage from 262 kilobytes up to about 2 megabytes depending on configuration. These constraints arose because core memory was expensive and physically bulky, often consisting of magnetic rings that limited scalability without significant hardware investment. Programs, however, frequently exceeded available memory; for instance, complex applications like scientific simulations or business processing could require more space than the entire addressable storage, halting execution unless managed through techniques like overlays. A key software factor exacerbating these hardware limits was the prevalence of monolithic executables in early programming environments, where entire programs were compiled and linked into single, indivisible load modules that needed to reside fully in for execution. In systems lacking built-in support for or segmentation, such as some pre-OS/360 environments, monolithic executables could not partially occupy , often leading to execution failures if the program's surpassed physical limits. However, OS/360 introduced facilities for overlays and to mitigate this. This enabled programmers to divide code into segments that could be loaded selectively, preventing outright execution halts. Overlays addressed these constraints by enabling the reuse of regions, thus permitting larger programs to run on resource-constrained machines without necessitating costly hardware upgrades. For example, in planned overlay structures, non-concurrent segments shared the same storage area, with only the root and active parts resident at any time, effectively multiplying usable program size beyond physical boundaries. This improved overall system efficiency, allowing early mainframes to handle sophisticated tasks like multiprogramming precursors. However, the approach introduced trade-offs, including elevated I/O overhead from frequent disk swaps to load overlay segments, which could degrade execution speed compared to fully in- programs, and required significant programmer effort to define structures without runtime optimization knowledge.

Implementation Mechanisms

Overlay Structures

Overlay structures in programming refer to the organizational frameworks that define how different modules or segments of a program share limited memory space by replacing one another at runtime. These structures are typically tree-based (hierarchical), where modules are arranged in a tree-like hierarchy with child modules replacing parent segments in designated memory areas. Tree-based structures allow for more efficient memory use in complex programs by enabling mutual exclusion among siblings—modules at the same level that do not execute concurrently. Key components of overlay structures include the , which outlines the relationships and loading positions of modules; the root segment, consisting of the non-overlayed base code that remains resident in throughout execution; and overlay regions, which are fixed blocks reserved for loading and swapping overlay modules. The serves as a blueprint generated by the linker, visually or programmatically representing the or sequence of segments to guide loading decisions. The root segment typically contains the program's and essential control logic, ensuring continuity, while overlay regions are sized to accommodate the largest module in a given path to avoid fragmentation. The design process for overlay structures involves the or explicitly specifying the layout through directives in , linker scripts, or control statements, which define segment groupings and their mutual exclusions. For instance, in systems like OS/360, programmers use OVERLAY and INCLUDE statements in the linkage editor input to assign modules to segments and regions, ensuring that dependent modules are structured hierarchically based on execution flow. This manual partitioning requires analyzing the program's to minimize overlaps and storage needs, often resulting in a where branches represent alternative execution paths. A representative example of a tree-based overlay can be visualized as follows: the segment, always in , branches to call either overlay A or overlay B, both of which load into the same overlay region, replacing the previous occupant as needed; from A, a child overlay C might then load into a sub-region, illustrating how siblings A and B share space without conflict. This design ensures that only the active path occupies at any time, optimizing for constraints like the 32K-word limit in early systems.

Dynamic Loading Process

At runtime, the overlay manager detects a call to an unloaded module by consulting a reference table that tracks the current state of loaded segments or routines. If the target overlay is not in , the manager saves the existing overlay to disk if it occupies the same , freeing up the necessary space; it then initiates an operation to read the new overlay from secondary storage, such as a , and updates the program's linkage pointers to point to the freshly loaded code and data. This stepwise swapping ensures seamless transitions between program phases while adhering to constraints. The overlay supervisor or driver serves as the central coordinator for these runtime actions, maintaining tables like the Overlay Name Table—which records metadata such as overlay identifiers, levels, sizes, and addresses—and the Overlay Reference Table, which maps specific routine calls to their overlay indices and entry points. These structures allow the supervisor to intercept calls, verify prerequisites, and trigger requests for loading, often using system macros like SEGLD in environments such as OS/360 to post event control blocks for . By handling relocation and linkage adjustments during loads, the supervisor preserves program integrity across swaps. Error handling mechanisms in the dynamic loading process mitigate risks from disk I/O failures, absent overlay files, or storage conflicts by performing pre-load validations and runtime checks. For example, if a disk read error occurs or an referenced routine is missing, the loader halts the operation, logs the issue in an error map or supervisory log, and may invoke an abnormal end routine to terminate the task while releasing allocated resources and notifying the operator. In cases of memory conflicts, the prioritizes unloading non-essential segments or aborts the load to avoid corruption, ensuring system stability. Disk seek and transfer latencies represent the main performance bottleneck in overlay swapping, as the process requires physical access to secondary storage for each load. On 1970s mainframe hardware, such as IBM's 2314 disk facility with average seek times of 60-75 milliseconds or the later 3330 model at 30 milliseconds, typical swap operations incurred delays of tens to low hundreds of milliseconds, potentially extending overall program load times by about 50% compared to non-overlaid execution. Despite this, execution overhead remained low—often under 1% increase—thanks to techniques like buffered preloading and optimized direct calls within active overlays.

Practical Examples

Basic Code Example

In a constrained memory environment, overlays enable a program larger than available RAM by loading mutually exclusive modules into the same region on demand. Consider a simple program consisting of a module that sequentially calls two functions, calc1 and calc2, which do not execute simultaneously and thus can share the same memory space. Each function requires 1 KB of memory, while the module needs 0.5 KB, resulting in a total program size of 2.5 KB. With only 1.5 KB of RAM available, overlays allow the program to run by reusing the memory slot for the functions. The following illustrates a basic overlay implementation using a manual overlay manager. The root loads calc1 initially, executes it, unloads it, loads calc2, and executes it. Module definitions are marked as overlays, and the manager handles from secondary storage (e.g., disk).

pseudocode

// Overlay Manager Functions function load_overlay(module_name, memory_address): read module_name from disk into memory_address // Assume module size fits in allocated slot function unload_overlay(memory_address): // Optional: clear or mark memory as free for reuse // Root Module (resident in memory, 0.5 KB) root_start: allocate_overlay_slot(1 KB) // Shared slot for calc1 and calc2 load_overlay("calc1", overlay_slot) call calc1 unload_overlay(overlay_slot) load_overlay("calc2", overlay_slot) call calc2 deallocate_overlay_slot end // Overlay Modules (stored on disk) // Marked as overlay in linker directives overlay calc1: // 1 KB // Computation logic for calc1 return overlay calc2: // 1 KB // Computation logic for calc2 return

// Overlay Manager Functions function load_overlay(module_name, memory_address): read module_name from disk into memory_address // Assume module size fits in allocated slot function unload_overlay(memory_address): // Optional: clear or mark memory as free for reuse // Root Module (resident in memory, 0.5 KB) root_start: allocate_overlay_slot(1 KB) // Shared slot for calc1 and calc2 load_overlay("calc1", overlay_slot) call calc1 unload_overlay(overlay_slot) load_overlay("calc2", overlay_slot) call calc2 deallocate_overlay_slot end // Overlay Modules (stored on disk) // Marked as overlay in linker directives overlay calc1: // 1 KB // Computation logic for calc1 return overlay calc2: // 1 KB // Computation logic for calc2 return

During execution, the root resides in the first 0.5 KB of RAM. When calc1 is called, the manager loads it into the next 1 KB slot, using 1.5 KB total and executing without overlap issues. After calc1 completes, unloading frees the slot for calc2, reusing the space and keeping total RAM usage at 1.5 KB despite the 2.5 KB program size. This manual approach relies on the programmer structuring calls to avoid simultaneous module needs. Such overlay mechanisms were commonly implemented in low-level assembly languages for systems with limited , including the PDP-11, where linkers like those in RT-11 or supported overlay directives to manage module loading.

Compiler-Generated Overlays

Compiler-generated overlays refer to the automated creation of overlay structures by compilers and associated tools, such as linkers, to manage in programs exceeding available main storage. In systems like IBM's OS/360, compilers for languages including FORTRAN IV (H Extended) and analyze the program's —representing procedure invocations and dependencies—to infer potential overlay hierarchies. This analysis identifies modules that can share regions based on non-overlapping execution paths, enabling the linker to generate an overlay tree during the linking phase. The overlay tree organizes the program into a root segment that remains resident and transient segments loaded on demand, optimizing storage utilization without requiring full manual specification. The process begins with the processing to produce object modules, incorporating annotations or metadata from programmer hints, such as procedure declarations or BLOCK DATA subprograms. For instance, in IV (H Extended), the examines call relationships to suggest segment groupings, which the linkage editor then refines into a structured load module using control statements like OVERLAY and INSERT. These statements define segment origins and insert control sections into specific overlay regions, with the editor automatically resolving external references and promoting common areas to shared segments. In , similar occurs through cataloged procedures like PL1LFCLG, which compile, link-edit, and execute overlay-enabled programs by processing object modules from libraries, ensuring external procedures are placed in appropriate segments based on call sequences. A prominent example is the linkage editor in IBM's OS/360, which generates overlays from source-derived annotations during the linking of or programs. Programmers provide initial structure via OVERLAY statements (e.g., OVERLAY ALPHA to define a segment), and the editor optimizes the tree by considering module sizes—for instance, positioning larger subprograms in dedicated overlays—and call frequencies to minimize the longest execution path's , potentially reducing requirements from 46,000 bytes to 15,000 bytes in multi-region designs. The editor's OVLY option enables this automated processing, producing a module map that details segment numbers and dependencies for runtime loading. This approach offers key advantages, including reduced manual errors in structuring complex programs and automatic handling of hierarchical dependencies that would be error-prone to define manually. By leveraging insights, it scales to larger applications, ensuring efficient segment sharing and without excessive intervention. However, limitations persist: non-obvious overlaps often require explicit hints through control statements or source attributes like EXTERNAL for STATIC variables, as the tools cannot fully infer all runtime behaviors. Moreover, such mechanisms have become outdated in modern optimizing compilers, which favor and just-in-time loading over static overlays.

Applications and Use Cases

In Legacy Operating Systems

In legacy operating systems like , overlays were implemented using separate .OVL files that the main executable () program loaded on demand into allocated memory segments. The EXEC function, invoked via 21h with AH=4Bh and AL=03h, enabled this loading without executing the overlay as an independent process, allowing the program to specify the target memory segment and relocation factor through a parameter block. The OS loader handled the overlay —often .COM or .EXE compatible—and performed the load operation, internally relying on calls (such as ) for disk access and data transfer to bypass the 640 KB limit. CP/M utilized its transient program area (TPA), typically up to 48-60 KB depending on system configuration, as the dedicated memory region for executing and swapping overlays in transient programs loaded from disk. Unlike , standard CP/M versions (e.g., 2.2) offered no native OS-level overlay support or dedicated system calls; instead, applications managed overlays manually by using BDOS functions for file I/O, such as function 0Fh (open file), 10h (close file), and 14h (read sequential) to read overlay segments from disk into the TPA and overwrite resident as needed. This program-driven approach required careful design to avoid conflicts, with the providing low-level disk services (e.g., via entry points for read/write) to facilitate the swaps. These overlay mechanisms significantly impacted legacy systems by enabling execution of programs larger than physical RAM—such as 100 KB+ applications on 64 KB or early UNIX machines—through selective loading, thereby simulating expanded memory and supporting complex software on single-tasking hardware without full support.

In Resource-Limited Environments

In resource-limited environments, such as 8-bit microcontrollers like the Intel 8051 and early game consoles with less than 32 KB of RAM, overlays enable the execution of programs exceeding available by dynamically swapping segments. The 8051, featuring only 128 or 256 bytes of internal data RAM and reliance on external expansion, employs overlay mechanisms in compilers to allocate shared physical spaces for mutually exclusive functions and data, preventing simultaneous residency of non-overlapping paths. This approach maximizes utilization of constrained resources, such as the 64 KB addressable program space, by loading only active modules on demand. Adaptations in these environments typically involve custom overlay managers embedded in , operating without operating system support and leveraging hardware features like flash or ROM swaps to transfer code into RAM. For instance, in bare-metal applications, linker tools generate overlay structures where segments are copied from non-volatile storage (e.g., external flash) to tightly coupled (TCM) during runtime, using manual invocation functions to ensure exclusivity and avoid conflicts. Such firmware-level implementations rely on call tree analysis during linking to identify overlayable areas, allowing efficient reuse of limited RAM without runtime overhead from an OS. In modern remnants, overlays see rare application in resource-constrained IoT devices for modular management, particularly where over-the-air updates require selective loading of components to conserve power and memory, though they have been largely supplanted by paging and flash partitioning in more capable systems.

Historical Context

Origins in Early Computing

The overlay technique originated in the early 1950s amid the constraints of systems on computers like the , which featured 2048 words (approximately 9 KB) of fast electrostatic storage, expandable to 4096 words (18 KB), supplemented by slower magnetic drum storage of up to 8192 words. Programmers addressed these limitations by manually swapping segments of code and data between core and drums or magnetic tapes, enabling execution of programs larger than available main memory—a method that became known as overlaying. This approach was essential in environments like , where the was installed in 1954, and techniques allowed modular coding to bypass memory size restrictions through strategic swapping. The input format of these systems further motivated overlays, as it permitted operators to load discrete program modules sequentially rather than attempting to fit an entire program into core at once, reducing the risk of memory overflow during scientific computations. Early efforts, such as John Backus's 1954 system for the —an interpretive tool for simplifying floating-point calculations—highlighted the challenges of programming in limited memory environments. By the early 1960s, overlays were formalized in monitors, particularly through the developed by the user group SHARE for the , to streamline scientific computing workflows. This milestone built directly on innovations from Backus's team at , who, starting in 1954, designed early compilers like the A-2 system to mitigate bottlenecks and enable compilation of complex algebraic expressions into efficient code. These advancements transformed manual swapping into a structured mechanism, prioritizing modular program design for resource-limited hardware.

Evolution and Obsolescence

During the 1970s, overlay techniques gained standardization in high-level programming languages like and , enabling developers to manage program segments more systematically on systems with limited RAM. In , support for overlays was formalized in the CODASYL specifications around 1968, with refinements in the 1970s American National Standard (ANS ) to facilitate segment-based loading for business applications. Similarly, compilers from , such as those for the System/360 in the early 1970s, incorporated overlay structures to handle complex scientific and data-processing tasks beyond available . This period also saw integration with minicomputers, exemplified by the DEC PDP-11 series, where overlays allowed executable code to exceed physical memory limits through manual segment swapping in RT-11 and other operating systems. Overlays reached their peak usage in the on personal computers, particularly under , where the 640 KB conventional memory barrier necessitated their use to run larger applications before affordable 1 MB RAM configurations became widespread around 1985. Their adoption declined sharply in the late and early as operating systems like 2.0 (1992) and (1993) introduced robust support, automating and reducing the need for manual overlay programming. The obsolescence of overlays stemmed primarily from hardware advancements, including the introduction of memory management units (MMUs) and paging mechanisms in processors like the Intel 80386 in 1985, which enabled efficient demand-paged virtual memory and seamless handling of programs larger than physical RAM. Swap files in modern operating systems further supplanted overlays by dynamically moving inactive pages to disk, eliminating the programmer's burden of explicit segment control. As of 2025, overlays persist in niche legacy codebases and resource-constrained , such as certain embedded systems using compilers, but they are largely relegated to educational contexts for understanding historical .

References

Add your contribution
Related Hubs
Contribute something
User Avatar
No comments yet.