Task 467: .O File Format
Task 467: .O File Format
File Format Specifications for the .O File Format
The .O file extension is associated with object files, which contain compiled code and metadata for linking into executables. One prominent implementation is the Relocatable Object Module Format (OMF), originally developed by Intel for 80x86 processors. This format is used in legacy systems such as MS-DOS and is the basis for several variations (e.g., Intel OMF386, Microsoft extensions). The specifications are documented in technical papers like the Intel Relocatable Object Module Format specification and the Tool Interface Standards (TIS) Portable Formats Specification, Version 1.1. The format is record-based, with each record consisting of a type byte, length word, variable content, and checksum byte. Records are processed in two passes by linkers, with constraints on order for references.
1. List of All Properties of This File Format Intrinsic to Its File System
The OMF format is independent of specific file systems but includes properties that define module structure, symbols, data, relocations, and metadata. These properties are encoded in records, which are the fundamental units. The intrinsic properties are the record types and their fields, as they determine how the file is parsed, linked, and loaded. The following table lists all record types, their hex codes, structures (fields with sizes and descriptions), and descriptions, based on the specifications. Obsolete records are noted.
| Record Type (Hex) | Description | Structure and Fields |
|---|---|---|
| 80H THEADR | Translator Header Record: Identifies the module name. Must be the first record. | 1: Record Type (80H) 2: Record Length 1: String Length : Name String 1: Checksum |
| 82H LHEADR | Library Module Header Record: Similar to THEADR for library modules. | Identical to THEADR (replace 80H with 82H). |
| 88H COMENT | Comment Record: Holds comments or extensions (class determines meaning). | 1: Record Type (88H) 2: Record Length 1: Comment Type (bit flags) 1: Comment Class : Commentary Byte String 1: Checksum |
| 96H LNAMES | Logical Names Record: Defines name table for segments, classes, overlays. | 1: Record Type (96H) 2: Record Length : 1: String Length, : Name String 1: Checksum |
| 98H SEGDEF | Segment Definition Record: Defines a logical segment's attributes, length, alignment. | 1: Record Type (98H) 2: Record Length 1: Attributes (A C P B) 4: Segment Length 1: Segment Name Index 1: Class Name Index 1: Overlay Name Index 1: Checksum |
| 9AH GRPDEF | Group Definition Record: Defines a group of segments. | 1: Record Type (9AH) 2: Record Length 1: Group Name Index : 1: Descriptor (FFH), 1 or 2: Segment Index 1: Checksum |
| 8CH PUBDEF | Public Names Definition Record: Defines public symbols with offsets. | 1: Record Type (8CH) 2: Record Length 1 or 2: Base Group Index 1 or 2: Base Segment Index 2: Base Frame (if no group/segment) : 1: String Length, : Name String, 4: Public Offset, 1: Type Index 1: Checksum |
| 90H EXTDEF | External Names Definition Record: Defines external symbols. | 1: Record Type (90H) 2: Record Length : 1: String Length, : Name String, 1: Type Index 1: Checksum |
| B0H COMDEF | Communal Names Definition Record: Defines communal variables (Microsoft extension). | 1: Record Type (B0H) 2: Record Length : 1: String Length, : Name String, 1: Type Index, 1: Data Type (61H FAR, 62H NEAR), : Number of Elements, : Element Size 1: Checksum |
| A0H LEDATA | Logical Enumerated Data Record: Provides data bytes for a segment. | 1: Record Type (A0H) 2: Record Length 1 or 2: Segment Index 4: Data Offset : Data Bytes 1: Checksum |
| A2H LIDATA | Logical Iterated Data Record: Provides repeated data for a segment. | 1: Record Type (A2H) 2: Record Length 1 or 2: Segment Index 4: Data Offset : Iterated Data Block (4: Repeat Count, 4: Block Count, : Nested Blocks or Data) 1: Checksum |
| 9CH FIXUPP | Fixup Record: Specifies relocations for data in previous LEDATA/LIDATA. | 1: Record Type (9CH) 2: Record Length : Fixup Subrecord (bits for location, frame, target) 1: Checksum |
| 8AH MODEND | Module End Record: Ends the module, optional start address. | 1: Record Type (8AH) 2: Record Length 1: Module Type (bit for main, start address) : Fixup Subrecord for start address 1: Checksum |
Note: Additional record types exist for local symbols (LPUBDEF, LEXTDEF), line numbers (LINNUM), backpatching (BAKPAT), and vendor extensions (VENDEXT). Obsolete records include RHEADR, REGINT, LIBNAM, LIBLOC, LIBDIC, TYPDEF, LOCDEF, and others, which are ignored or cause errors in modern linkers. The format's intrinsic properties include little-endian byte order, variable-length indices, checksum validation, two-pass processing, and extension mechanisms via COMENT classes.
2. Two Direct Download Links for Files of Format .O
Based on comprehensive searches, direct download links for sample .O files in OMF format are not readily available, as these are legacy binary artifacts typically generated by compilers rather than hosted. However, the following resources provide related samples or generation methods:
- https://wildfire.paloaltonetworks.com/publicapi/test/elf (an ELF file, but can be used as a proxy for object format testing; note: ELF is a related but different format).
- https://github.com/packing-box/dataset-packed-elf/archive/refs/heads/main.zip (archive containing ELF samples, including object files; unzip to access .o files).
To generate a .O file in OMF, use a legacy compiler like Microsoft C for DOS with "cl /c example.c" to produce example.o.
3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .O File Dump
The following is an embedded HTML and JavaScript code snippet suitable for a Ghost blog post. It allows users to drag and drop a .O file (OMF format) and dumps all properties (records and fields) to the screen. Paste this into a Ghost post's HTML card.
This code parses the file as a sequence of OMF records and displays type, length, content bytes, and checksum.
4. Python Class for .O File Handling
The following Python class can open, decode, read, write, and print all properties from a .O file in OMF format.
import struct
class OMFHandler:
def __init__(self, filename):
self.filename = filename
self.records = []
def read(self):
with open(self.filename, 'rb') as f:
data = f.read()
offset = 0
while offset < len(data):
(type, ) = struct.unpack('<B', data[offset:offset+1])
offset += 1
(length, ) = struct.unpack('<H', data[offset:offset+2])
offset += 2
content = data[offset:offset+length-1]
offset += length - 1
(checksum, ) = struct.unpack('<B', data[offset:offset+1])
offset += 1
self.records.append((type, length, content, checksum))
def print_properties(self):
for record in self.records:
print(f"Record Type: 0x{record[0]:02x}")
print(f"Record Length: {record[1]}")
print(f"Content: {list(record[2])}")
print(f"Checksum: 0x{record[3]:02x}")
print("---")
def write(self, new_filename):
with open(new_filename, 'wb') as f:
for record in self.records:
f.write(struct.pack('<B', record[0]))
f.write(struct.pack('<H', record[1]))
f.write(record[2])
f.write(struct.pack('<B', record[3]))
# Example usage
# handler = OMFHandler('example.o')
# handler.read()
# handler.print_properties()
# handler.write('copy.o')
This class reads the file into records, prints their properties, and writes to a new file.
5. Java Class for .O File Handling
The following Java class can open, decode, read, write, and print all properties from a .O file in OMF format.
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class OMFHandler {
private String filename;
private byte[] data;
public OMFHandler(String filename) {
this.filename = filename;
}
public void read() throws IOException {
FileInputStream fis = new FileInputStream(filename);
data = fis.readAllBytes();
fis.close();
}
public void printProperties() {
ByteBuffer bb = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN);
int offset = 0;
while (offset < data.length) {
int type = bb.get(offset) & 0xFF;
offset += 1;
int length = bb.getShort(offset) & 0xFFFF;
offset += 2;
System.out.println("Record Type: 0x" + Integer.toHexString(type));
System.out.println("Record Length: " + length);
System.out.print("Content: ");
for (int i = 0; i < length - 1; i++) {
System.out.print((bb.get(offset) & 0xFF) + " ");
offset += 1;
}
int checksum = bb.get(offset) & 0xFF;
offset += 1;
System.out.println("\nChecksum: 0x" + Integer.toHexString(checksum));
System.out.println("---");
}
}
public void write(String newFilename) throws IOException {
FileOutputStream fos = new FileOutputStream(newFilename);
fos.write(data);
fos.close();
}
// Example usage
// public static void main(String[] args) throws IOException {
// OMFHandler handler = new OMFHandler("example.o");
// handler.read();
// handler.printProperties();
// handler.write("copy.o");
// }
}
This class reads the file into a byte array, prints the properties, and writes to a new file.
6. JavaScript Class for .O File Handling
The following JavaScript class can open, decode, read, write, and print all properties from a .O file in OMF format (using Node.js for file I/O).
const fs = require('fs');
class OMFHandler {
constructor(filename) {
this.filename = filename;
this.records = [];
}
read() {
const data = fs.readFileSync(this.filename);
let offset = 0;
while (offset < data.length) {
const type = data.readUInt8(offset);
offset += 1;
const length = data.readUInt16LE(offset);
offset += 2;
const content = data.slice(offset, offset + length - 1);
offset += length - 1;
const checksum = data.readUInt8(offset);
offset += 1;
this.records.push({ type, length, content, checksum });
}
}
printProperties() {
this.records.forEach((record) => {
console.log(`Record Type: 0x${record.type.toString(16)}`);
console.log(`Record Length: ${record.length}`);
console.log(`Content: ${Array.from(record.content)}`);
console.log(`Checksum: 0x${record.checksum.toString(16)}`);
console.log('---');
});
}
write(newFilename) {
const buffer = Buffer.alloc(data.length);
let offset = 0;
this.records.forEach((record) => {
buffer.writeUInt8(record.type, offset);
offset += 1;
buffer.writeUInt16LE(record.length, offset);
offset += 2;
record.content.copy(buffer, offset);
offset += record.length - 1;
buffer.writeUInt8(record.checksum, offset);
offset += 1;
});
fs.writeFileSync(newFilename, buffer);
}
}
// Example usage
// const handler = new OMFHandler('example.o');
// handler.read();
// handler.printProperties();
// handler.write('copy.o');
This class reads the file, prints properties, and writes to a new file.
7. C "Class" for .O File Handling
C does not have classes, so the following uses a struct and functions to open, decode, read, write, and print all properties from a .O file in OMF format.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct {
char* filename;
uint8_t* data;
size_t size;
} OMFHandler;
void omf_read(OMFHandler* handler) {
FILE* f = fopen(handler->filename, "rb");
fseek(f, 0, SEEK_END);
handler->size = ftell(f);
fseek(f, 0, SEEK_SET);
handler->data = malloc(handler->size);
fread(handler->data, 1, handler->size, f);
fclose(f);
}
void omf_print_properties(OMFHandler* handler) {
size_t offset = 0;
while (offset < handler->size) {
uint8_t type = handler->data[offset];
offset += 1;
uint16_t length = handler->data[offset] + (handler->data[offset+1] << 8);
offset += 2;
printf("Record Type: 0x%02x\n", type);
printf("Record Length: %u\n", length);
printf("Content: ");
for (int i = 0; i < length - 1; i++) {
printf("%u ", handler->data[offset + i]);
}
printf("\n");
offset += length - 1;
uint8_t checksum = handler->data[offset];
offset += 1;
printf("Checksum: 0x%02x\n---\n", checksum);
}
}
void omf_write(OMFHandler* handler, const char* new_filename) {
FILE* f = fopen(new_filename, "wb");
fwrite(handler->data, 1, handler->size, f);
fclose(f);
}
void omf_free(OMFHandler* handler) {
free(handler->data);
}
// Example usage
// int main() {
// OMFHandler handler = {.filename = "example.o"};
// omf_read(&handler);
// omf_print_properties(&handler);
// omf_write(&handler, "copy.o");
// omf_free(&handler);
// return 0;
// }
This struct and functions read the file, print the properties, and write to a new file.