[comp.os.minix] fixing strip

webber@csd.uwo.ca (Robert E. Webber) (11/21/90)

In article <9011192110.AA15043@decpa.pa.dec.com> cranston@guru.dec.com (Scott Cranston) writes:
>strip(1) on MacMinix does not work.  The origional flavor before the a.out.h
>patch that Joe Pickert posted (part of ps(1) fixes) would not recognize
>a file as an executable.  After recompiling strip using the new a.out.h
>it now runs.  However, when I recompile a command and then strip it I get
>a SYSTEM BOMB ID=10.
> 
>Any ideas or fixes?

A less drastic way of observing the problem is that nm on a normal executable
reports the symbol table, on one of the supplied executables, it reports
nothing, but on a stripped executable it reports
    can't read symbol table
Insertion of print messages into nm shows the following behavior:
   cp nm bin/nm
   nm bin/nm >/dev/null
does an lseek to location 6782 and then reads a table of size 1808
   ls -l bin/nm
reports a file size of 8860
   strip bin/nm
   nm bin/nm >/dev/null
does an lseek to location 6782 and then reads a table of size 1808.
however, since
   ls -l bin/nm
reports that the file is now 7020 bytes long, the above read only reads
238 bytes and then reports that it can't read the symbol table since the
value from read is less than the length to read.

the amount of table read is gotten from header.a_syms (header is of
type exec which is defined in a.out.h) which is long and so is anded
with 0xFFFF and cast to int before being passed to read.  the lseek
is made to location A_SYMPOS(header) where A_SYMPOS is a macro also
defiined in a.out.h.

A_SYMPOS(X) expands to:
   ((long)header.a_hdrlen) + header.a_text + header.a_data +
        ((header.a_hdrlen > (unsigned char) 32) ? 
                 header.a_trsize + header.a_drsize : 0)

a_hdrlen is of type unsigned char; all the other quantities are size long.

in this case, a_hdrlen is 0 and a_text is 6260 and a_data is 522 (both
stripped and unstripped).

looking at old stripped executables, the big difference seems to be
that a_syms should be set to 0 for a stripped executable.

looking at the code to strip.c, we see that a_syms is set to 0L.  it
is then written out to disk using write_header which writes an image
of length a_hdrlen.  since a_hdrlen is 0 (as observed above), this
is less than totally thrilling.  

looking back at read_header, we find that it reads a minimum buffer
of A_MINHDR and then reads more if a_hdrlen is larger than 
sizeof (struct exec).  A_MINHDR has the value 32.

changing write_header to:
    write_header(fd)
     int fd;
     { int WriteLength;
       WriteLength = A_MINHDR;
       if (WriteLength < (int) header.a_hdrlen)
               WriteLength = (int) header.a_hdrlen;
       lseek(fd, 0L, SEEK_SET);
       if (write(fd, (char *) & header, WriteLength) != WriteLength)
           return(1);
       return(0);
      }

fixed the nm reading problem.  however, I still get a system bomb when I
try to execute a stripped binary, specifically ID = 28.

Looking over the code, the only place in strip.c where the symbol
table could be skipped over was the lseek done after the text and data
space had been copied.  This lseek is conditional on a test of
relo_size (which is long) against the integer 0.  relo_size at the
moment turns out to be 194.  Since it is non-zero, an lseek of length
symb_size gets done.  symb_size is the old value of header.a_syms.

relo_size is the difference between st_size coming back from fstating
the program and A_MINHDR plus the a_text, a_data, and symb_size.
This looks like relo_size is going to be wrong if header is ever
bigger than A_MINHDR, but that apparently isn't the case at the moment.

The particular lseek that skips over symp_size uses whence set to 1
(which in <unistd.h> is SEEK_CUR relative to current position).

This is all messed up because read_header first reads A_MINHDR bytes
and then skips back to the beginning of the file and reads a_hdrlen
bytes.  Since, a_hdrlen is 0, this means that the later reads are
32 bytes off where they should be from.  This variable size header
stuff doesn't make much sense to me (doubtless it has to do with
compatibility with code that I am not seeing (mm/exec.c always reads
32 bytes and then skips over anything else)).  So, changed read_header
along the lines of write_header above, i.e., introducing a ReadLength
variable and then making sure that ReadLength is the max of A_MINHDR
and a_hdrlen and doing the read at length ReadLength (thus ensuring 
we don't do any reads of length 0 for the same reasons we don't want 
to do writes of length 0).  

Now stripped programs seem to work just fine and don't bomb my system
and nm works too on stripped programs.  Since the only changes were to
strip.c, don't think any other behavior changed.  Seems to me that
strip was built assuming that the compiler would put 32 in a_hdrlen,
but the compiler/loader actually put 0 there.  Not having source to
the compiler/loader, I don't know why it is putting 0 there.  Am sort
of curious how the distributed programs were stripped given that the
distributed strip program couldn't possibly work unless the compiler
that built the unstripped programs was setting a_hdrlen to 32 or
greater (which the distributed compiler on a Mac+ clearly does not).

--- BOB (webber@csd.uwo.ca)

archetyp@uxh.cso.uiuc.edu (Joseph R Pickert) (11/28/90)

webber@csd.uwo.ca (Robert E. Webber) writes:

>In article <9011192110.AA15043@decpa.pa.dec.com> cranston@guru.dec.com (Scott Cranston) writes:
>>strip(1) on MacMinix does not work.  The origional flavor before the a.out.h
>>patch that Joe Pickert posted (part of ps(1) fixes) would not recognize
>>a file as an executable.  After recompiling strip using the new a.out.h
>>it now runs.  However, when I recompile a command and then strip it I get
>>a SYSTEM BOMB ID=10.
>> 
>>Any ideas or fixes?

>A less drastic way of observing the problem is that nm on a normal executable
>reports the symbol table, on one of the supplied executables, it reports
>nothing, but on a stripped executable it reports
>    can't read symbol table
>Insertion of print messages into nm shows the following behavior:
>   cp nm bin/nm
>   nm bin/nm >/dev/null
>does an lseek to location 6782 and then reads a table of size 1808
>   ls -l bin/nm
>reports a file size of 8860
>   strip bin/nm
>   nm bin/nm >/dev/null
>does an lseek to location 6782 and then reads a table of size 1808.
>however, since
>   ls -l bin/nm
>reports that the file is now 7020 bytes long, the above read only reads
>238 bytes and then reports that it can't read the symbol table since the
>value from read is less than the length to read.

I am aware of these problems.  The ultimate cause is the a.out.h file.
I will post a new one soon.

Joe Pickert