In article <
341826d2-1682-415f...@googlegroups.com>,
No.
>edx appears to be used to contain the cluster number:
>
> andl $-16, %edx
`%ebx` contains your cluster number, not `%edx`.
>From the AND here:
That is not from the logical `and` in the next stanza.
> cluster = (buf[offset]
> | ((unsigned long)buf[offset + 1] << 8)
> | ((unsigned long)buf[offset + 2] << 16)
> | ((unsigned long)buf[offset + 3] << 24))
> & 0x0fffffff;
>
>But this code wipes the value:
>
> xorl %edx, %edx
I should hope so, since you're doing a division after this and
the numerator fits in %eax.
>And the value would have been corrupt anyway because of this:
>
> movb _buf.8+3(%edx), %dl
What do you mean, "corrupt?" `%edx` holds an offset into some
buffer at the beginning of this instruction; that offset is not
used after this instruction, so the compiler chose to load a
byte into the register. That byte is eventually OR'd into the
"cluster" value in `%ebx`.
Let's go through this section-by-section.
>L665:
> subl $8, %esp
Allocate some space on the stack. Why? To keep it aligned for
the call to `_fatEndCluster`.
> pushl %ebx
> pushl %edi
Push the arguments to `_fatEndCluster` onto the stack.
> call _fatEndCluster
Execute that call....
> addl $16, %esp
Deallocate the stack space allocated above. Note: it would look
like both `%ebx` and `%edi` could be clobbered here, but I'm
guessing you're using the "cdecl" calling convention, where
`%ebi` is callee-save.
> testl %eax, %eax
Did the call to `fatEndCluster` return zero?
> jne L689
If not, go to 689 (terminates the loop).
> movl 92(%edi), %eax
Move the `fat->fat_type` member into `%eax`.
> cmpl $16, %eax
> je L690
If `fat_type == 16`, branch to the code that handles that.
> cmpl $12, %eax
> je L691
If `fat_type == 12`, branch to the code that handles that.
>L671:
> cmpl $32, %eax
> jne L665
If `fat_type` is not 32, branch to the top of the loop. Note
that there is no case for handling bad data here; even minor
corruption could lead to an infinite loop.
> xorl %edx, %edx
Clear `%edx` for the division.
> leal 0(,%ebx,4), %eax
Move `cluster*4` into `%eax`.
> movl 16(%edi), %ecx
Copy `fat->sector_size` into `%ecx`.
> divl %ecx
Divide `cluster*4` (`%eax`) by `fat->sector_size` (in `%ecx`)
the quotient is placed in `%eax`. Note that this is why `%edx`
was cleared above (it is part of the numerator). After this
`%edx` contains `(cluster*4)%fat->sector_size`.
> movl %eax, %esi
Copy the quotient to `%esi`; see below about the modulus part in
`%edx`.
> addl 48(%edi), %esi
Add `fat->fat_sector` to the quotient. `%esi` is now
`fatSector`.
> cmpl %esi, -16(%ebp)
Compare `fatSector` to `buffered`.
> je L681
If they're equal, skip the next few instructions.
> movl -16(%ebp), %eax
> testl %eax, %eax
> jne L692
If `buffered != 0`, jump to whatever code handles that.
>L682:
> pushl %eax
> pushl $_buf.8
> pushl %esi
> pushl %edi
> call _fatReadLogical
Now push the arguments to `_fatReadLogical` onto the stack and
call it. Note that this will clobber `%eax` and `%edx`, and the
latter of held the value `(cluster*4)%fat->sector_size`. The
rest of the arguments to `_fatReadLogical` are callee-safe.
`$_buf.8` is a static, so just a pointer.
> movl %esi, -16(%ebp)
Copy `fatSector` to `buffered`.
> addl $16, %esp
Clean up the stack after the call to `_fatReadLogical`.
> movl 16(%edi), %ecx
As above, copy `fat->sector_size` into `%ecx`.
>L681:
> leal 0(,%ebx,4), %eax
Load `cluster*4` into %eax. Note that this is where the program
lands if `buffered` was equal to what was calculated for
`fatSector` above.
> xorl %edx, %edx
Clear `%edx` for the division.
> divl %ecx
Execute the division. `%edx` is now `offset`.
One may note, at this point, that `%edx` already contained this
value, so why recompute it here? As mentioned above, it was
likely clobbered by the call to `_fatReadLogical`.
> movzbl _buf.8+1(%edx), %eax
Load `buf[offset+1]` into `%eax`.
> movzbl _buf.8(%edx), %ebx
Copy `buf[offset]` into `%ebx`.
> sall $8, %eax
Arithmetic shift left 8 bits `%eax` so that it is
`buf[offset+1]<<8`.
> orl %eax, %ebx
Set `%ebx` to `(buf[offset+1]<<8)|buf[offset]`;
> movzbl _buf.8+2(%edx), %eax
Load `buf[offset+2]` into `%eax`.
> movl %edx, %ecx
Save a copy of `offset` into `%ecx`.
> sall $16, %eax
Set `%eax` to `buf[offset+2]<<16`.
> movb _buf.8+3(%edx), %dl
Load `buf[offset+3]` into `dl`.
> orl %eax, %ebx
Or `buf[offset+2]<<16` into %ebx.
At this point, `%ebx` is set to the value of,
`buf[offset]|(buf[offset+1]<<8)|(buf[offset+2]<<16)`.
> movl %edx, %eax
> sall $24, %eax
This moves `buf[offset+3]<<24` into `%eax`.
> orl %eax, %ebx
Or `buf[offset+3]<<24` into `%ebx`, which is now:
```
(unsigned)buf[offset] |
((unsigned)buf[offset + 1] << 8) |
((unsigned)buf[offset + 2] << 16) |
((unsigned)buf[offset + 3] << 24)
```
> andl $-16, %edx
Recall that `%edx` holds the value of `buf[offset + 3]`; this
clears the low 4-bits of that byte. That is, this sets %edx to
`buf[offset + 3] & 0xF0`. It is used a few instructions down.
> andl $268435455, %ebx
268435455 == 0x0FFFFFFF, so this is `%ebx & 0x0FFFFFFF`. And
now, `%ebx` is equal to:
```
((unsigned)buf[offset] |
((unsigned)buf[offset + 1] << 8) |
((unsigned)buf[offset + 2] << 16) |
((unsigned)buf[offset + 3] << 24)) &
0x0FFFFFFF
```
`%ebx` is now the newly computed value of `cluster`.
> movb $0, _buf.8(%ecx)
This sets `buf[offset]` to 0.
> movb $0, _buf.8+1(%ecx)
Similarly for `buf[offset + 1]`.
> movb $0, _buf.8+2(%ecx)
Similarly for `buf[offset + 2]`.
> movb %dl, _buf.8+3(%ecx)
Recall at this point that `%edx` contains the value of
`buf[offset + 3] & 0xF0`. This copies that byte to back into
`buf[offset + 3]` .
> incl -24(%ebp)
This increments `deletedclusters`.
> jmp L665
And finally jumps back up to the top of the loop.
The code appears to be correct given the source code.
- Dan C.