About Me
Welcome to my blog! This is where I collect my observations and notes on programming and technology. The main subjects range from implementation details to broader ideas about programming.
Main Topics
- Engineering Projects: Exploring implementation details and how technical systems work.
- C/C++: Notes on language features and programming techniques.
- The Programmer’s Perspective: Ideas about developing a career and a way of thinking as a programmer.
For more, visit the categories page.
Contact
If you have questions or would like to discuss something, please get in touch through the About page.
Thank you for reading and for your support. I hope these notes help you on your own technical journey!
Assembly addresses and load addresses
An assembly-time label is a numerical address in the assembler’s model. If a program is loaded elsewhere, the loader or program must apply the appropriate relocation. In the boot-sector exercise, physical 0x7C00 must agree with the chosen origin or vstart convention.
I/O interfaces and ports
Devices communicate through interface circuitry. The source’s ICH description refers to a particular chipset organization, not every computer. A device specification determines register widths and access rules. Architectures can provide memory-mapped I/O, a separate I/O address space, or both.
For the 16-bit x86 IN forms, the destination is AL or AX. A port can be encoded as an 8-bit immediate, covering ports 0–255, or supplied in DX, allowing the wider port space. OUT follows the corresponding rules in the opposite direction. IN and OUT do not modify arithmetic flags. Data width and port-number width are separate choices.
The source calls its ATA addressing example LBA23; the familiar legacy ATA scheme in this context is LBA28. It also infers a maximum of 255 sectors from an 8-bit count register at 0x1F2. Command encodings require consulting their specification: in classic 28-bit ATA sector-count semantics, zero represents 256 sectors. Register width alone does not establish every command’s transfer limit.
Procedure calls
A procedure is also called a routine. In the discussed assembler context, a call without a far qualifier normally selects a near form.
A relative near call encodes a displacement from the next instruction. An indirect near call obtains the destination offset from a register or memory operand. A far call changes both segment and offset, saving a far return address on the stack. In the 16-bit case it pushes the old CS and then the return IP, leaving IP on top.
A direct far pointer is encoded with offset before segment. An indirect far call reads the complete far pointer from memory; a single general register is not enough to hold that 16:16 pointer in the 8086 form.
RET pops a near return offset. RETF pops the offset and segment. These ordinary calls and returns do not restore or otherwise modify flags as an interrupt return does.
A label is a numerical assembly symbol, often denoting an offset. It is not a macro that inserts the target’s source text.
Shifts and rotates
For the original 8086, a shift count is one or comes from CL. Later processors add immediate-count forms. Thus shr ax,1 has a compact encoding such as D1 E8, while shr ax,5 uses a later encoding such as C1 E8 05. ROR and ROL rotate rather than shifting zeros into the vacated positions.
Jump forms
A short relative jump uses an 8-bit signed displacement, -128 through 127. A near relative 16-bit jump uses a 16-bit displacement. An indirect near jump takes an absolute offset within the current code segment from a register or memory.
A direct far jump supplies segment and offset. An indirect far jump reads them from memory, with the offset word first and segment word second. Each word is itself stored little-endian; the word ordering should not be confused with switching the whole pointer to big-endian.
Program initialization
A loaded program initializes the data and stack segments required by its own conventions. Its code entry and initial CS are established by the loader’s transfer of control. The order matters if a header is temporarily accessed through a segment register that will later be repurposed.
NASM’s RESB, RESW, and RESD reserve byte, word, and doubleword storage without defining initialized contents. Immediate pushes are available on later x86 processors, not the original 8086.
External interrupts
The historical interface uses INTR for maskable requests and NMI for non-maskable requests. The 8259 programmable interrupt controller supplies vector information for maskable interrupts. Real-mode NMI uses vector 2.
NMI often reports serious conditions, but it is not inherently unrecoverable; platforms also use it for debugging or watchdog purposes. The original notes’ assertion that nearly every NMI is fatal is too broad.
An interrupt vector contains offset followed by segment. A BIOS may initialize unused entries to a simple return handler, but software must not assume every unused vector is safe. IRET restores interrupt return state.
RTC access
Some historical CMOS/RTC access sequences control NMI through the index port. Reading time also requires avoiding an update that would mix fields from different instants. Temporarily controlling interrupts alone does not guarantee a consistent snapshot; the device’s update protocol matters. The original explanation focused on interruption delays and should be read as an incomplete motivation.
Useful instructions and PIC acknowledgment
HLT stops ordinary instruction execution until an eligible event resumes it. NOT complements its operand without changing flags. TEST computes an AND-like flag result without storing the result back to either operand.
An 8259 tracks in-service interrupts. A handler normally sends an end-of-interrupt command when required by its configuration; it does not directly overwrite the internal in-service register as ordinary memory. Correct acknowledgment permits later requests at the relevant priorities.
Internal exceptions and software interrupts
Later x86 processors use vector 6 for invalid opcode; this should not be generalized to every behavior of the original 8086. Synchronous exceptions are not masked by IF. Software INT instructions also avoid the external interrupt-acknowledge bus sequence.
INT3 has a dedicated one-byte breakpoint encoding. An assembler’s treatment of int 3 may choose that encoding, so source spelling alone does not always establish a different instruction. INTO generates vector 4 when OF is set in supported legacy modes; it is not available in 64-bit mode.
Handlers can be installed by software with the required control of the execution environment. Protected-mode permissions constrain what an ordinary application can replace.
Firmware and option ROMs
Parts of physical A0000h–FFFFFh are historically reserved for video memory and firmware. Legacy BIOS systems scan relevant option-ROM regions for a 55 AA signature, inspect the size field, validate a checksum, and may call an initialization entry.
Correction to the original description: the third byte is conventionally a size in 512-byte units, rather than the checksum value to compare directly. A valid image has the prescribed checksum over its declared length. Exact scan regions and policies depend on the firmware. Device initialization code can install interrupt service entries.
Entering 32-bit programming
Neither IP nor EIP is an ordinary MOV destination. Control-flow instructions update them. Protected-mode memory access uses segment selectors and cached descriptor information, including bases, limits, and permissions. Hardware checks enforce the relevant rules.
A flat 32-bit arrangement uses segments with base zero and a broad address range, often 4 GiB. The programmer-visible segment selector remains 16 bits; the processor also caches hidden descriptor state. FS and GS add segment registers beyond the older four. The 80286 introduced protected-mode facilities with a 24-bit physical address capability even though its visible segment selectors remained 16 bits.
Why paging helps
Allocating variable-size contiguous regions for tasks can leave external fragmentation: total free memory may suffice while no single gap fits a large request. Paging maps virtual pages to physical frames, reducing the need for large contiguous physical regions and supporting isolation and virtual memory. A common x86 page size is 4 KiB, with other page sizes available on suitable processors.
If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !