This is mach-o.pl in view mode; [Download] [Up]
#!/usr/bin/perl
# $Id: mach-o.pl,v 1.0 92/07/31 17:39:42 cap Exp $
# Utility functions for reading and writing Mach-O files
#
# constants from include files
$LC_SEGMENT = 1; # segment of file to be mapped
$sizeof_mach_header = 4 + 4*2 + 4*4;
sub read_mach_header {
local($handle) = @_;
local($buf);
seek($handle, 0, 0);
read($handle, $buf, $sizeof_mach_header);
# ($magic, $cputype, $cpusubtype, $filetype, $ncmds, $sizeofcmds, $flags) =
unpack("Li2L4", $buf);
}
#
# peek a load command, which is presumably at the current file pointer location
# This returns the command type and size, and then seeks back to before
# where it read.
$sizeof_load_command = 4 + 4;
sub peek_load_command {
local($handle) = @_;
local($buf);
read($handle, $buf, $sizeof_load_command);
seek($handle, -$sizeof_load_command, 1); # back up
# ($cmd, $cmdsize) =
unpack("L2", $buf);
}
#
# Read and return a segment command
$sizeof_segment_command = 4*2 + 16 + 4*8;
sub read_segment_command {
local($handle) = @_;
local($buf);
read($handle, $buf, $sizeof_segment_command);
# ($cmd, $cmdsize, $segname, $vmaddr, $vmsize, $fileoff, $filesize,
# $maxprot, $initprot, $nsects, $flags) =
unpack("L2A16L4i2L2", $buf);
}
#
# seek past a segment, whose segment_command we've already read
# You pass in the file handle and cmdsize of the segment
sub seek_past_segment_command {
local($handle, $cmdsize) = @_;
seek($handle, $cmdsize - $sizeof_segment_command, 1);
}
# the segment structure is passed in as the arguments, and
# the structure is written at the current file pointer, leaving
# the file pointer after the structure
sub write_segment_command {
local($handle, @structure) = @_;
local($buf);
$buf = pack("L2a16L4i2L2", @structure);
print $handle $buf;
};
#
# Read and return a section command
$sizeof_section_command = 16 + 16 + 4*9;
sub read_section_command {
local($handle) = @_;
local($buf);
read($handle, $buf, $sizeof_section_command);
# struct section {
# char sectname[16]; /* name of this section */
# char segname[16]; /* segment this section goes in */
# unsigned long addr; /* memory address of this section */
# unsigned long size; /* size in bytes of this section */
# unsigned long offset; /* file offset of this section */
# unsigned long align; /* section alignment (power of 2)*/
# unsigned long reloff; /* file offset of relocation entries */
# unsigned long nreloc; /* number of relocation entries */
# unsigned long flags; /* flags (i.e. zero fill section, etc)*/
# unsigned long reserved1; /* reserved */
# unsigned long reserved2; /* reserved */
# };
unpack("A16A16L9", $buf);
}
# There's no support for reading fvmlib, fvmlib_command, thread_command,
# symtab_command, symseg_command, and ident_command information,
# because I don't need that stuff.
## Now some higher-level functions
# this finds a segment, reads and returns its information structure,
# and leaves the file pointer right after the structure
sub segment_info {
local($handle, $seg) = @_;
local($magic, $cputype, $cpusubtype, $filetype, $ncmds, $sizeofcmds,
$flags);
local($cmdnum, @seginfo);
seek($handle, 0, 0);
($magic, $cputype, $cpusubtype, $filetype, $ncmds, $sizeofcmds, $flags) =
&read_mach_header($handle);
SEGMENTS:
for ($cmdnum = 0; $cmdnum < $ncmds; $cmdnum++) {
# read the load_command struct
($cmd, $cmdsize) = &peek_load_command($handle);
if ($cmd != $LC_SEGMENT) {
seek($section, $cmdsize, 1); # skip this command
} else {
@seginfo = &read_segment_command($handle);
if (@seginfo[2] ne $seg) {
# skip to next command
&seek_past_segment_command($handle, $cmdsize);
} else {
last SEGMENTS;
}
}
}
@seginfo;
}
# section_info
# This leaves the file pointer right after the found section structure,
# or after the last section or command if the requested information wasn't
# found
sub section_info {
local($handle, $sect, $seg) = @_;
local($magic, $cputype, $cpusubtype, $filetype, $ncmds, $sizeofcmds,
$flags);
local($cmdnum, @sectinfo);
seek($handle, 0, 0);
($magic, $cputype, $cpusubtype, $filetype, $ncmds, $sizeofcmds, $flags) =
&read_mach_header($handle);
SEGMENTS:
for ($cmdnum = 0; $cmdnum < $ncmds; $cmdnum++) {
# read the load_command struct
($cmd, $cmdsize) = &peek_load_command($handle);
if ($cmd != $LC_SEGMENT) {
seek($section, $cmdsize, 1); # skip this command
} else {
($cmd, $cmdsize, $segname, $vmaddr, $vmsize, $fileoff, $filesize,
$maxprot, $initprot, $nsects, $flags) =
&read_segment_command($handle);
if ($segname ne $seg) {
# skip to next command
&seek_past_segment_command($handle, $cmdsize);
} else {
for ($sectnum = 0; $sectnum < $nsects; $sectnum++) {
@sectinfo = &read_section_command($handle);
last SEGMENTS if (@sectinfo[0] eq $sect);
}
}
}
}
@sectinfo;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.