home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 10 / AU_CD10.iso / Updates / Perl / Non-RPC / !Perl / riscos / RISCOS / AOF.pm < prev    next >
Text File  |  1998-07-31  |  10KB  |  409 lines

  1. package RISCOS::AOF::Symbol;
  2. use Carp;
  3. use strict;
  4. use vars qw (@ISA $VERSION);
  5.  
  6. $VERSION = 0.03;    # Now that I have access to AOF 3.11 info
  7. # 0.03 uses map
  8. @ISA = qw();
  9.  
  10. sub new ($$$$$) {
  11.     my $proto = shift;
  12.     my $class = ref($proto) || $proto;
  13.     my $self  = {};
  14.     my ($name, $at, $value, $area, $stringtable) = @_;
  15.  
  16.     return undef unless defined ($self->{__NAME} = 
  17.       RISCOS::AOF::aof_string_from_table ($stringtable, $name));
  18.     
  19.     $self->{__AT} = $at ||= 0;
  20.     carp sprintf "AT field in " . $self->{__NAME} 
  21.       . " with value %08X contains unknown bits", $at if (~0xB7F & $at);
  22.     
  23.     
  24.     $self->{__AREA} = &RISCOS::AOF::aof_string_from_table ($stringtable, $area)
  25.       unless ($at & 5 == 1);
  26.         
  27.     $self->{__VALUE} = $value
  28.       if ($at & 0x41);    # Bit 0 or 6 set
  29.  
  30.     $self->{__SCOPE} = ('Unknown', 'static', 'extern', '')[$at & 3];
  31.  
  32.     my $misc = [];
  33.     
  34.     if ($at & 3 == 2) {
  35.     push @$misc, 'case insensitive' if $at & 8;
  36.     push @$misc, 'weak' if $at & 0x10;
  37.     push @$misc, 'common area' if $at & 0x40;
  38.     } elsif ($at & 3 == 3) {
  39.     push @$misc, 'strong' if $at & 0x20;
  40.     }
  41.     
  42.     push @$misc, 'code datum' if $at & 0x100;
  43.     push @$misc, 'FP args in FP regs' if $at & 0x200;
  44.     push @$misc, 'simple leaf function' if $at & 0x800;
  45.  
  46.     $self->{__MISC} = $misc if @$misc;
  47.         
  48.     bless ($self, $class);
  49. }
  50.  
  51. sub Name {
  52.     my $self = shift;
  53.     $self->{'__NAME'};
  54. }
  55.  
  56. sub Value {
  57.     my $self = shift;
  58.     return $self->{__VALUE} unless defined $self->{__AREA};
  59.     "$self->{__VALUE} relative to area '$self->{__AREA}'";
  60. }
  61.  
  62. sub Defined {
  63.     my $self = shift;
  64.     $self->{__AT} & 1;
  65. }
  66.  
  67. sub Scope {
  68.     my $self = shift;
  69.     $self->{'__SCOPE'};
  70. }
  71.  
  72. sub Misc {
  73.     my $self = shift;
  74.     @{$self->{'__MISC'}};
  75. }
  76.  
  77. package RISCOS::AOF;
  78. require RISCOS::Chunkfile;
  79.  
  80. require Exporter;
  81. use Carp;
  82. use strict;
  83. use vars qw (@ISA $VERSION @EXPORT_OK);
  84.  
  85. $VERSION = 0.02;
  86. @ISA = qw(Exporter RISCOS::Chunkfile);
  87. @EXPORT_OK = qw(aof_symboltable aof_string_from_table);
  88.  
  89. sub new ($$) {
  90.     my $proto = shift;
  91.     my $class = ref($proto) || $proto;
  92.     
  93.     my $self = $class->SUPER::new ($_[0]);
  94.     
  95.     foreach my $what (qw(OBJ_HEAD OBJ_AREA OBJ_IDFN OBJ_SYMT OBJ_STRT)) {
  96.     if ($self->Multiple ($what)) {
  97.         carp "AOF file has '$what' chunks at positions "
  98.          . join (' ', @{$self->Lookup ($what)})
  99.           if $^W;
  100.         return undef;
  101.     }
  102.     }
  103.     
  104.     my $chunk = $self->Chunk ('OBJ_HEAD');
  105.     
  106.     unless (defined $chunk) {
  107.     carp "AOF has no 'OBJ_HEAD'" if $^W;
  108.     return undef;
  109.     }
  110.     
  111.     unless ($chunk->Length() >= 12) {
  112.     carp "AOF header is far too short" if $^W;
  113.     return undef;
  114.     }
  115.     my ($type, $version, $num_area, $num_sym, $entry_area, $entry_offset)
  116.       = unpack 'I6', (my $head_data = $chunk->Data());
  117.     
  118.     if ($type != 0xC5E2D080) {
  119.     if ($^W) {
  120.         if ($type == 0xC5E2D081) {
  121.         carp 'Don\'t understand AOF Image type 1';
  122.         } elsif ($type == 0xC5E2D083) {
  123.         carp 'Don\'t understand AOF Image type 2';
  124.         } elsif ($type == 0xC5E2D087) {
  125.         carp 'Don\'t understand AOF Image type 3';
  126.         } else {
  127.         carp sprintf "Don't understand unknown AOF type &%8X", $type;
  128.         }
  129.     }
  130.     return undef;
  131.     }
  132.     
  133.     unless ($chunk->Length() == 24 + 20 * $num_area) {
  134.     carp "AOF header reports $num_area area(s) - expect length to be "
  135.          . (24 + 20 * $num_sym) . ' bytes, actually ' . $chunk->Length()
  136.          . 'bytes ' if $^W;
  137.     return undef;
  138.     }
  139.     
  140.     $self->{'VERSION'} = sprintf "%2f", $version / 100;
  141.     if ($entry_area) {
  142.     $self->{'ENTRY_AREA'} = $entry_area - 1;
  143.     $self->{'ENTRY_OFFSET'} = $entry_offset;
  144.     }
  145.     
  146.     if (defined ($chunk = $self->Chunk ('OBJ_SYMT'))) {
  147.     $self->{'SYMBOLS'}
  148.       = aof_symboltable ($chunk, $self->Chunk ('OBJ_STRT'))
  149.     }
  150.     
  151.     $chunk = $self->Chunk ('OBJ_AREA');
  152.     
  153.     unless (defined $chunk) {
  154.     carp "AOF has no 'OBJ_AREA'" if $^W;
  155.     return undef;
  156.     }
  157.     
  158.     $self->{'AREAS'} = [];
  159.     
  160.     my $offset = 24;
  161.     
  162.     while ($num_area--) {
  163.     # Eventually this needs to be "new" object consisting of
  164.     # name (will need symtable in place already)
  165.     # ALignment
  166.     # ATtributes
  167.     # (Size) from Data - hmm - what to do about zero init - use undef?
  168.     # (Number of relocations) - from Data
  169.     # Base address
  170.         
  171.     push @{$self->{'AREAS'}}, substr $head_data, $offset, 20;
  172.     $offset += 20;
  173.     }
  174.     
  175.     $self;
  176. }
  177.  
  178. sub String ($;@) {
  179.     my $self = shift;
  180.     my $stringtable = \($self->Chunk ('OBJ_STRT')->Data());
  181.     return undef unless $stringtable and defined $_[0];
  182.  
  183.     return aof_string_from_table ($stringtable, $_[0]) unless wantarray;
  184.     map  { aof_string_from_table ($stringtable, $_) } @_;
  185. }
  186.  
  187. sub Creator ($) {
  188.     my $self = shift;
  189.     # Strip the trailing nulls
  190.     ($self->Chunk ('OBJ_IDFN')->Data()) =~ /^([^\0]+)\0/s;
  191.     
  192.     $0;
  193. }
  194.  
  195. sub Version ($) {
  196.     my $self = shift;
  197.     $self->{'VERSION'};
  198. }
  199.  
  200. sub Symbols ($) {
  201.     my $self = shift;
  202.     $self->{'SYMBOLS'};
  203. }
  204.  
  205. #
  206. # Subroutines from the pre-OO version.
  207. #
  208. sub aof_stringtable ($) {
  209.     return undef unless defined (my $chunk = shift);
  210.  
  211.     # And the PRM says
  212.     # "The length stored at the start of the string table itself is identically
  213.     #  the length stored in the OBJ_STRT chunk header."
  214.     # And "ARM AOF Macro Assembler 3.06 (Acorn Computers Ltd)" stores
  215.     # 168 in the chunk header, but 166 at the start of the table
  216.     # (rink's o.rink_rtsys)
  217.     # Nice one Acorn
  218.     # So we will round them up to a multiple of 4
  219.     
  220.     unless (((3 + unpack ('V', $chunk)) & ~3) == ((3 + length $chunk) & ~3)) {
  221.     carp sprintf "Stringtable reports length as %d, actually %d",
  222.              unpack ('V', $chunk),length $chunk
  223.       if $^W;
  224.     return undef;
  225.     }
  226.  
  227.     my $entries = {};
  228.     $chunk = substr $chunk, 4;
  229.     my $pos = 4;
  230.  
  231.     while ($chunk =~ /([^\0]+)/s) {
  232.     $entries->{$pos} = $1;
  233.     $pos += 1 + length $1;
  234.     $chunk = substr $chunk, 1 + length $1;
  235.     }
  236.  
  237.     $entries;
  238. }
  239.  
  240. # Because strictly some bugger can write a stringtable with
  241. # "....realloc\0" where 'alloc' is offset 6 and 'realloc' is offset 4
  242. sub aof_string_from_table ($$) {
  243.     my ($ref, $offset) = @_;
  244.     return $ref->{$offset} if ref $ref eq 'HASH';
  245.     
  246.     return undef unless ref $ref eq 'LVALUE' or ref $ref eq 'SCALAR';
  247.     
  248.     (substr $$ref, $offset) =~ /^([^\0]+)\0/s;
  249.     
  250.     $1;
  251. }
  252.  
  253. sub aof_symboltable ($$) {
  254.     return undef unless defined (my $chunk = shift);
  255.  
  256.  
  257.     my ($stringtable) = @_;
  258.     my $symboltable;
  259.  
  260.     unless (ref $stringtable) {
  261.     carp "aof_symboltable not passed a reference" if $^W;
  262.     return ();
  263.     }
  264.  
  265.     if (ref $stringtable eq 'RISCOS::Chunk') {
  266.     if ($stringtable->ID ne 'OBJ_STRT') {
  267.         carp "aof_symboltable passed a reference to '" . $stringtable->ID
  268.           . "', not a stringtable" if $^W;
  269.         return ();
  270.     }
  271.     $stringtable = \$stringtable->Data;    # Ref to scalar data
  272.     }
  273.     elsif (ref $stringtable ne 'HASH') {
  274.     carp "aof_symboltable not passed a recognised reference" if $^W;
  275.     return ();
  276.     }
  277.     
  278.     if (ref $chunk eq 'RISCOS::Chunk') {
  279.     if ($chunk->ID ne 'OBJ_SYMT') {
  280.         carp "aof_symboltable passed a reference to '" . $chunk->ID
  281.           . "', not a symboltable" if $^W;
  282.         return ();
  283.     }
  284.     $chunk = $chunk->Data;
  285.     }
  286.  
  287.     if (0xF & length $chunk) {
  288.     carp "symbol table length " . length $chunk 
  289.       . " is not a multiplte of 16" if $^W;
  290.     return ();
  291.     }
  292.     my $result = [];
  293.     while ($chunk =~ s/(.{16})//s) {
  294.     my $symbol = new RISCOS::AOF::Symbol unpack ('V4', $1), $stringtable;
  295.     push @$result, $symbol if defined $symbol;
  296.     }
  297.     
  298.     $result;
  299. }
  300. 1;
  301. __END__
  302.  
  303. =head1 NAME
  304.  
  305. RISCOS::AOF -- manipulate ARM Object Format files
  306.  
  307. =head1 SYNOPSIS
  308.  
  309.     use RISCOS::AOF;
  310.     
  311.     my $obj_file = new RISCOS::AOF $file;
  312.     foreach my $symbol (@{$obj_file->Symbols}) {
  313.     print $symbol->Name(), "\n" if $symbol->Scope eq 'extern';
  314.     }
  315.  
  316. =head1 DESCRIPTION
  317.  
  318. C<RISCOS::AOF> provides a class derived from C<RISCOS::Chunkfile> to manipulate
  319. the contents of B<A>RM B<O>ject B<F>ormat files. It provides a class
  320. C<RISCOS::AOF::Symbol> to store details of each symbol in an C<AOF> file.
  321.  
  322. Currently the implementation is incomplete - only methods to manipulate the
  323. symbol table have been written. Methods to manipulate area data are currently
  324. unimplemented.
  325.  
  326. =head2 Methods
  327.  
  328. =over 4
  329.  
  330. =item new <array_ref>
  331.  
  332. =item new <file>
  333.  
  334. If passed a reference to an array it is assumed to be an array of
  335. C<RISCOS::Chunk> objects to use as the file contents. Otherwise calls
  336. C<RISCOS::File::load> to loads the file specified using and checks that it is
  337. C<AOF>. Hence I<file> can be a filename, a reference to a filehandle, or a
  338. reference to a scalar which is used as the file's contents.
  339.  
  340. If passed an array reference then this is used internally in the object, so
  341. should be created with the anonymous array constructor C<[]> rather than a
  342. reference to a named array variable (see  L<perldsc/Common Mistakes>).
  343.  
  344. Returns undefined if there was an error, or the file contents are corrupt.
  345.  
  346. =item String <offset> [...]
  347.  
  348. Looks up strings in the stringtable.
  349.  
  350. In scalar context returns the string at the first offset given. In array context
  351. returns the list of strings referred to by the supplied list of offsets.
  352.  
  353. =item Creator
  354.  
  355. Returns whatever string is stored in the C<OBJ_IDFN> chunk - typically a
  356. string identifying the creator of the C<AOF> file.
  357.     
  358. =item Version
  359.  
  360. Returns the version number from the C<AOF> file.
  361.  
  362. =item Symbols
  363.  
  364. Returns a reference to the array of C<RISCOS::AOF::Symbol> objects describing
  365. the symbols in the C<AOF> file.
  366.  
  367. =back
  368.  
  369. =head1 RISCOS::AOF::Symbol
  370.  
  371. The C<RISCOS::AOF::Symbol> class is used to hold information about a symbol in
  372. an C<AOF> file. The class provides the following methods to access this
  373. information:
  374.  
  375. =over 4
  376.  
  377. =item Name
  378.  
  379. Returns the symbol name.
  380.  
  381. =item Value
  382.  
  383. Returns the symbol value. If the symbol is absolute then this is just a number.
  384. Otherwise it is a string of the form "C<I<value> relative to area 'I<area>'>".
  385.  
  386. =item Defined
  387.  
  388. Returns true if the symbol is defined in this C<AOF> file. Returns false if it
  389. is defined externally.
  390.  
  391. =item Scope
  392.  
  393. Returns the scope of the symbol ('C<static>', 'C<extern>' or '').
  394.  
  395. =item Misc
  396.  
  397. Returns an array of strings describing other properties of the symbol - I<e.g.>
  398. 'C<case insensitive>', 'C<weak>', 'C<strong>', 'C<common area>'.
  399.  
  400. =back
  401.  
  402. =head1 BUGS
  403.  
  404. As noted, methods to manipulate areas are currently unimplemented.
  405.  
  406. =head1 AUTHOR
  407.  
  408. Nicholas Clark <F<nick@unfortu.net>>
  409.