Attached a simple bytecode header reader/writes that writes out the
natively correct output, and can read in recognize the output of "any"
(for small enough values of any) other platform.  Tried on x86 (32LE),
sparc (32BE), alpha (64LE), mips (32BE/64BE, compiler-switchable), and
unicosmk (64BE, really an alpha, not true Cray CPU).

Compile as 'cc -o pbh -I/perl5/include pbh.h' and use as
./pbh -o pbh.foo (write) or ./pbh -i pbh.bar (read).

I confess to cutting down Dan's spec a bit, by changing the
major/minor to be bytes, and moving the cookie to the end
(for better alignment), now this basic header is only 16 bytes.

An interesting detail is that (in case UVSIZE == 4) even if I write
the 0x1234567 to the char offset 8, the long might end up beginning
at offset 12... this is what happens in the MIPS, as opposed to Sparc
where the long lands at offset 8 as expected.  Probably some funky
alignment issue that I'm much too sleepy to ponder now.

In case we want 8-byte magic signature "PARROTRY" would work,
just as an idle observation :-)

-- 
$jhi++; # http://www.iki.fi/jhi/
        # There is this special biologist word we use for 'stable'.
        # It is 'dead'. -- Jack Cohen
/*
 * Copyright 2001 Jarkko Hietaniemi.  All rights reserved.
 * This is free software. It may be used, redistributed
 * and/or modified under the same terms as Perl itself. */

#include "EXTERN.h"
#include "perl.h"

#define PARROT_BYTECODE_MAJOR   0
#define PARROT_BYTECODE_MINOR   1

#define PARROT_BYTECODE_IO_SUCCESS       0
#define PARROT_BYTECODE_IO_FAILURE      -1
#define PARROT_BYTECODE_MAGIC_FAILURE   -2
#define PARROT_BYTECODE_EMPTY_FAILURE   -3

typedef struct {
    U8  wordsize;
    int major;
    int minor;
    U8  cookie[8];
} parrot_bytecode_header;

#define PARROT_BYTECODE_HEADER_SIZE (4+1+1+1+1+8)

#define PARROT_BYTECODE_HEADER_MAGIC    0
#define PARROT_BYTECODE_HEADER_WORDSIZE 4
#define PARROT_BYTECODE_HEADER_MAJOR    5
#define PARROT_BYTECODE_HEADER_MINOR    6
#define PARROT_BYTECODE_HEADER_EMPTY    7
#define PARROT_BYTECODE_HEADER_COOKIE   8

int
parrot_bytecode_header_read(FILE *fp, parrot_bytecode_header *pbh)
{
     U8 buffer[PARROT_BYTECODE_HEADER_SIZE];

     if (fread(buffer, PARROT_BYTECODE_HEADER_SIZE, 1, fp) == 1) {
          if (!(buffer[PARROT_BYTECODE_HEADER_MAGIC    ] == 'P' &&
                buffer[PARROT_BYTECODE_HEADER_MAGIC + 1] == 'A' &&
                buffer[PARROT_BYTECODE_HEADER_MAGIC + 2] == 'R' &&
                buffer[PARROT_BYTECODE_HEADER_MAGIC + 3] == 'R'))
               return PARROT_BYTECODE_MAGIC_FAILURE;
          pbh->wordsize = buffer[PARROT_BYTECODE_HEADER_WORDSIZE];
          pbh->major    = buffer[PARROT_BYTECODE_HEADER_MAJOR];
          pbh->minor    = buffer[PARROT_BYTECODE_HEADER_MINOR];
          if (buffer[PARROT_BYTECODE_HEADER_EMPTY])
               return PARROT_BYTECODE_EMPTY_FAILURE;
          memcpy(pbh->cookie,
                 buffer + PARROT_BYTECODE_HEADER_COOKIE,
                 sizeof(pbh->cookie));
          return PARROT_BYTECODE_IO_SUCCESS;
     }
     else
          return PARROT_BYTECODE_IO_FAILURE;
}

int
parrot_bytecode_header_write(FILE *fp)
{
     U8 buffer[PARROT_BYTECODE_HEADER_SIZE] = { 0 };

     buffer[PARROT_BYTECODE_HEADER_MAGIC    ] = 'P';
     buffer[PARROT_BYTECODE_HEADER_MAGIC + 1] = 'A';
     buffer[PARROT_BYTECODE_HEADER_MAGIC + 2] = 'R';
     buffer[PARROT_BYTECODE_HEADER_MAGIC + 3] = 'R';

     buffer[PARROT_BYTECODE_HEADER_WORDSIZE] = UVSIZE;

     buffer[PARROT_BYTECODE_HEADER_MAJOR]    = PARROT_BYTECODE_MAJOR;
     buffer[PARROT_BYTECODE_HEADER_MINOR]    = PARROT_BYTECODE_MINOR;
     
#undef COOKIE
#if UVSIZE == 8
     ((UV*)(buffer + PARROT_BYTECODE_HEADER_COOKIE))[0] =
         0x123456789abcdef0;
#else
#   if UVSIZE == 4
     ((UV*)(buffer + PARROT_BYTECODE_HEADER_COOKIE))[0] =
         0x12345678;
#   else
     memset(buffer + PARROT_BYTECODE_HEADER_COOKIE, -1, 8);
#   endif
#endif

     if (fwrite(buffer, PARROT_BYTECODE_HEADER_SIZE, 1, fp) == 1) {
          return PARROT_BYTECODE_IO_SUCCESS;
     }
     else
          return PARROT_BYTECODE_IO_FAILURE;
}

void
parrot_bytecode_header_dump(FILE *fp, parrot_bytecode_header *pbh)
{
     fprintf(fp, "wordsize = %d\n", pbh->wordsize);
     fprintf(fp, "major    = %d\n", pbh->major);
     fprintf(fp, "minor    = %d\n", pbh->minor);
     fprintf(fp, "cookie   = %02x%02x%02x%02x%02x%02x%02x%02x\n",
             pbh->cookie[0], pbh->cookie[1], pbh->cookie[2], pbh->cookie[3],
             pbh->cookie[4], pbh->cookie[5], pbh->cookie[6], pbh->cookie[7]);
}

void show_usage_and_die(char *argv[])
{
     fprintf(stderr, "Usage: %s [-o|-i] file\n", argv[0]);
     exit(1);
}

int
main(int argc, char *argv[])
{
     if (argc == 3) {
          FILE *fp;

          if (strEQ(argv[1], "-o")) {
               if ((fp = fopen(argv[2], "wb"))) {
                    parrot_bytecode_header_write(fp);
                    fclose(fp);
               }
               else {
                    fprintf(stderr, "fopen(\"%s\", \"w\") failed: %s\n",
                            argv[2], strerror(errno));
                    exit(2);
               }
          } else if (strEQ(argv[1], "-i")) {
               if ((fp = fopen(argv[2], "rb"))) {
                    parrot_bytecode_header pbh;

                    parrot_bytecode_header_read(fp, &pbh);
                    parrot_bytecode_header_dump(stderr, &pbh);
                    fclose(fp);
               }
               else {
                    fprintf(stderr, "fopen(\"%s\", \"r\") failed: %s\n",
                            argv[2], strerror(errno));
                    exit(2);
               }
          } else
               show_usage_and_die(argv);
     } else
          show_usage_and_die(argv);
     return 0;
}

Reply via email to