#!/usr/bin/perl # -*- perl -*- # $Header: /home/johnl/book/linker/code/RCS/readobj.pl,v 1.4 2001/07/23 05:08:23 johnl Exp $ # Project code for Linkers and Loaders by John R. Levine, # published by Morgan-Kauffman in October 1999, ISBN 1-55860-496-0. # # This code is copyright 2001, John R. Levine. Permission is granted # to individuals to use this code for non-commercial purposes in # unmodified or modified form. Permission is also granted to # educational institutions to use this code for educational purposes # in unmodified or modified form. Other uses, such as including it # in a product or service offered for sale, require permission from # the author. # ################################################################ # readobj: read and write object files # # In each of the hashes below, there may be extra fields beyond # the ones listed # # An object file is a hash with these fields: # name => file or archive name, if any # nseg => # of segments # nsym => # of symbols # nrel => # of relocs # segnames => hash names to segment numbers (below) # segs => [] array of segments # symnames => hash names to symbol numbers # syms => [] array of symbols (below) # rels => [] array of relocs (below) # # A segment is a hash with these fields: # segno => segment number # base => base address as a number (not a hex string) # size => size as a number (not a hex string) # flags => flag characters # data => data as a byte string (not a hex string) # # A symbol is a hash with these fields: # name => symbol name # symno => symbol number # value => symbol value as a number (not a hex string) # seg => segment number # type => type # # A reloc is a hash with these fields: # loc => location # seg => segment number # ref => reference segment or symbol number # type => relocation type # # get a line, skip blank and comments, trim off newline sub getl(*) { my ($handle) = @_; while(1) { my $l = <$handle>; die "Unexpected EOF" unless defined($l); next if $l =~ /^#/; # comment next if $l =~ /^\s*$/; # blank line chomp($l); return $l; } } sub readobject($) { my ($filename) = @_; my ($l, $i); open(OBJ, $filename) or die "cannot open $filename"; $l = getl(OBJ); # check the header, get the counts die "$filename not an object file" unless $l eq "LINK"; my %o; $o{name} = $filename; ($o{nseg}, $o{nsym}, $o{nrel}) = split ' ',getl(OBJ); # read in the segment descriptions for $i (1..$o{nseg}) { my ($segname, $base, $size, $flags) = split ' ',getl(OBJ); $o{segs}->[$i] = { name => $segname, segno => $i, base => hex($base), size => hex($size), flags => $flags }; $o{segnames}->{$segname} = $i; } # read in the symbol table for $i (1..$o{nsym}) { my ($symname, $value, $seg, $type) = split ' ',getl(OBJ); $o{syms}->[$i] = { name => $symname, symno => $i, value => hex($value), seg => $seg, type => $type }; $o{symnames}->{$symname} = $i; } # read in the relocations for $i (1..$o{nrel}) { my ($loc, $seg, $ref, $type, $extra) = split ' ',getl(OBJ), 5; $o{rels}->[$i] = { loc => hex($loc), seg => $seg, ref => $ref, type => $type, extra => $extra }; } # slurp in the data for $i (1..$o{nseg}) { my $s = $o{segs}->[$i]; next if $s->{flags} !~ /P/; # bss type not present my $t = getl(OBJ); my $slen = 2 * $s->{size}; die "data for $s->{name} is wrong size" unless length($t) == $slen; $s->{data} = pack "H$slen", $t; } close OBJ; \%o; } ################################################################ sub writeobject($%) { my ($filename, $oref) = @_; my ($l, $i); my %o = %$oref; open(OBJ, ">$filename") or die "cannot open $filename"; print OBJ "LINK\n"; print OBJ "$o{nseg} $o{nsym} $o{nrel}\n"; # write out the segment descriptions for $i (1..$o{nseg}) { my $s = $o{segs}->[$i]; printf OBJ "%s %x %x %s\n", $s->{name}, $s->{base}, $s->{size}, $s->{flags}; } # write out the symbol table for $i (1..$o{nsym}) { my $s = $o{syms}->[$i]; printf OBJ "%s %x %d %s\n", $s->{name}, $s->{value}, $s->{seg}, $s->{type}; } # write out the relocations for $i (1..$o{nrel}) { my $r = $o{rels}->[$i]; printf OBJ "%x %d %d %s", $r->{loc}, $r->{seg}, $r->{ref}, $r->{type}; print OBJ " $r->{extra}" if $r->{extra} != ""; print OBJ "\n"; } # dump out the data for $i (1..$o{nseg}) { my $s = $o{segs}[$i]; next if $s->{flags} !~ /P/; # bss type not present print OBJ unpack "H*",$s->{data}; print OBJ "\n"; } close OBJ; } 1;