[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: ARM710 problems

On Sat, Mar 03, 2001 at 12:00:19PM +0000, Philip Blundell wrote:
> It's certainly very strange. Perhaps you could try disassembling the
> gzip that works for you, and comparing it to one that doesn't. If
> that doesn't yield any clues then I think the only thing for it is
> for you to dig into one of the crashing binaries with the debugger
> and find out what it is that makes it go wrong.

I've looked at it some more, but haven't found the cause. It seems
like either argv[0] is corrupted somewhere, or parameters get
corrupted e.g. when the program calls glibc. The generated code for
gzip's main() is very different, no idea what's happening in either
version of the binary. The code for basename() is identical. I guess I
will have to try with gdb. <sigh>

I hardly know anything about what happens before a program's main() is
executed under Linux. Where's the best place to look? Also, where can
I get information about ELF?

It would be nice to have a crashing version of gzip with debugging
symbols. (I compiled gzip on rameau yesterday, but that binary works. 
Still have to try debussy.) Where did the gzip in question (=current
potato version) get compiled?

This is what happens:

When gzip is invoked, it calls one of its functions, basename(), to
strip e.g. '/usr/bin/' from argv[0]:

    int main (argc, argv) int argc; char **argv; {
        int file_count;     /* number of files to precess */
        int proglen;        /* length of progname */
        int optc;           /* current option */
        progname = basename(argv[0]);
basename() calls glibc's strrchr():

    char *basename(fname) const char *fname; {
        char *p;
        if ((p = strrchr(fname, PATH_SEP))  != NULL) fname = p+1;
        if ('A' == 'a') strlwr(fname); /* optimized away */
        return fname;

 2009230:       e1a0c00d        mov     ip, sp
 2009234:       e92dd810        stmdb   sp!, {r4, fp, ip, lr, pc}
 2009238:       e24cb004        sub     fp, ip, #4      ; 0x4
 200923c:       e1a04000        mov     r4, r0
 2009240:       e3a0102f        mov     r1, #47 ; 0x2f
 2009244:       ebffde6d    [5] bl      0x2000c00       ; <== strrchr()
 2009248:       e3500000        cmp     r0, #0  ; 0x0
 200924c:       12800001        addne   r0, r0, #1      ; 0x1
 2009250:       01a00004        moveq   r0, r4
 2009254:       e91ba810        ldmdb   fp, {r4, fp, sp, pc}
In glibc, strrchr makes a call to strchr(), which is weak-aliased to index():

    char *
    strrchr (const char *s, int c) {
      register const char *found, *p;
      c = (unsigned char) c;
      /* Since strchr is fast, we use it rather than the obvious loop.  */
      if (c == '\0')
        return strchr (s, '\0');
      found = NULL;
      while ((p = strchr (s, c)) != NULL) {
          found = p;
          s = p + 1;
      return (char *) found;
   7b30c:       e1a0c00d        mov     ip, sp
   7b310:       e92dd830        stmdb   sp!, {r4, r5, fp, ip, lr, pc}
   7b314:       e24cb004        sub     fp, ip, #4      ; 0x4
   7b318:       e1a04001        mov     r4, r1
   7b31c:       e21440ff        ands    r4, r4, #255    ; 0xff
   7b320:       1a000002        bne     0x7b330
   7b324:       e1a01004        mov     r1, r4
   7b328:       ebfe8bb3        bl      0x1e1fc
   7b32c:       e91ba830        ldmdb   fp, {r4, r5, fp, sp, pc}
   7b330:       e3a05000        mov     r5, #0  ; found = NULL
   7b334:       ea000001    [4] b       0x7b340 ; while
   7b338:       e1a05000        mov     r5, r0
   7b33c:       e2850001        add     r0, r5, #1      ; 0x1
   7b340:       e1a01004    [2] mov     r1, r4
   7b344:       ebfe9190        bl      0x1f98c ; strchr(s, c)
   7b348:       e3500000        cmp     r0, #0  ; 
   7b34c:       1afffff9    [3] bne     0x7b338
Finally, the crash occurs in index():

    char *
    strchr (s, c_in) const char *s; int c_in; {
      const unsigned char *char_ptr;
      const unsigned long int *longword_ptr;
      unsigned long int longword, magic_bits, charmask;
      unsigned reg_char c;
      c = (unsigned char) c_in;
      /* Handle the first few characters by reading one character at a time.
         Do this until CHAR_PTR is aligned on a longword boundary.  */
      for (char_ptr = s; ((unsigned long int) char_ptr
                          & (sizeof (longword) - 1)) != 0; ++char_ptr)
        if (*char_ptr == c)
          return (void *) char_ptr;
        else if (*char_ptr == '\0')
          return NULL;

   79e30:       e1a0c00d    [1] mov     ip, sp
   79e34:       e92dd810        stmdb   sp!, {r4, fp, ip, lr, pc}
   79e38:       e24cb004        sub     fp, ip, #4
   79e3c:       e1a03000        mov     r3, r0          ; char_ptr = s
   79e40:       e3130003        tst     r3, #3  ; 0x3
   79e44:       e20110ff        and     r1, r1, #255    ; c = (uchar) c_in;
   79e48:       0a000007        beq     0x79e6c
   79e4c:       e5d30000        ldrb    r0, [r3] ; <== CRASH HERE
    *** Segmentation fault
    Register dump:
     R0: 00000001   R1: 0000002f   R2: bffffb9c   R3: 00000001
     R4: 0000002f   R5: 00000000   R6: 02000a18   R7: 400207a4
     R8: 00000001   R9: 02000fe4   SL: 4013c2c8   FP: bffffb0c
     IP: bffffb10   SP: bffffafc   LR: 400a7348   PC: 400a5e4c
     CPSR: 20000010
     Trap: 0000000e   Error: 00000002   OldMask: 00000000

The register dump implies that at [1] strchr() was called with R0=1. 
Thus, R0 must also have been 1 at [2].
[2] could only be reached via the branch at [4]; R0 would have
had to be 0 at [3], but in that case that branch is not taken.
Thus, R0 was 1 on entry to strrchr(), and also when strrchr() was
called at [5].



  __   _
  |_) /|  Richard Atterer     |  CS student at the Technische  |  GPG key:
  | \/¯|  http://atterer.net  |  Universität München, Germany  |  888354F7
  ¯ ´` ¯

Reply to: