[comp.sys.atari.st.tech] How to set variables

72347.2767@CompuServe.COM (Robert Delius Royar) (11/15/90)

Re: your question posted to comp.sys.atari.st.tech for info on how to modify
variables in an executable file, there are a number of ways.

I assume you need to modify the variables in a disk file--i.e. you are not
looking to change them in a running program, to un-fixup the program, and then
to write them back to disk.  That could get real hary.  I can think of two
easy ways to accomplish this.  One requires some assembly.  The other requires
you to leave symbols in the executable.  I'll describe the former.  The latter
is the method used by GNU C top do just what you are looking for.

Finding the executable on disk

The first step is to find the executable on disk.  This may be easy or
difficult depending on the TOS level and on the type of program you are
running.  TOS does not store the name of the currently executing process in
an accessible place, but the AES does store this if you Pexec from an AES
program and use the following in your init routine, before adjusting paths
and such:
    char myname[128], command[128];
    appl_init();
    shel_read(myname,command);
Unfortunately before Rainbow TOS, the rscrc_load() function and others trash
the shel_read() buffers.  TOS 1.4 onward doesn't exhibit this problem.  On
return from shel_read() myname will contain the name (and possibly the path)
of the executing process.  Command will contain the command from the
invocation of myname.

A simpler way to find the name is to require that it remain constant and
to require the program be invoked from its own directory.  Then you don't
have to find it--it's always where you expect.

Modifying variables

The TOS executable format requires each program (even overlays) to begin with
a 28-byte header.  This header "disappears" once the program is loaded for
execution.  More accurately, parts of it are stored in the executable's
basepage.  The so-called magic number (0x60 0x1a) that must be at the start of
every executable file is actually a bra.b 0x1a instruction, which on earlier
Alcyon 68K systems caused execution to begin at 28 bytes passed the
beginning.  TOS does not interpret the magic the same way, but execution
begins with the first address of the .text which is 28 bytes past beginning of 
the header.  The effect is the same.

You can store variables right after the beginning of the .text as long as you
jump around those variables.  With a little figuring, you can safely modify
those variables on disk and save the results.  Here are some code fragments:

*  This fragment sets up the variable table
*  Must be first object file in link statement
*
.globl    __start    * this is the runtime entry routine in gemstart.s
.globl    _vartab
.globl    _var1
.globl    _var2
.globl    _var3
            jmp    __start
_vartab:
_var1:        dc.l    0
_var2:        dc.l    0
_var3:        dc.l    0

/* this C fragment opens the file, finds the current variable values, and
 * changes them
 */
    char buf[3*sizeof(long)];
    char myname[128], command[128];

    appl_init();
    shel_read(myname,command);
    if ((fd=Fopen(myname,2)) < 0) {
        Cconws("Cannot open ");
        Cconws(myname);
        Cconws("\r\n");
        Pterm(fd);
    } else
        Fseek(0x22L,fd,0);    /* now points to vartab */
    Fread(fd,(long)(3*sizeof(long)),buf);
    modify_buf(buf);    /* make your changes */
    Fseek(0x22L,fd,0);    /* 0x1c + sizeof(jmp __start) == 0x22L */
    Fwrite(fd,(long)(3*sizeof(long)),buf);    /* write them back */
    Fclose(fd);

I've used the above in a number of programs without problems.  Hope yo find
this useful.

Robert Royar
Cratylus Educational Software