[ ... ]
Note that I said "an address range" -- this wouldn't necessarily be the
case with all its memory.
Assuming its char was 8 bits, each of those 32-bit items
would have to be given four different addresses -- even if you could
only read or write anything via one of them.
Hm, now you have confused me again. How would pointer arithmetic work on
that machine for
char banner [20];
for ( char * iter = &banner; iter != &banner+20; ++ iter ) {
*iter = 0;
}
(or whatever, I am not good at raw arrays and pointer so there may be syntax
issues).
The implementation has two choices. The first is if you've defined
something as a char, it allocates it in a different address range that
allows byte-level access. In this case, your code works fine, but if you
tried something like:
int x;
char *y = &x;
y[1] = 0;
In this case, we've defined an int, so it allocates memory that's only
accessible on word boundaries. Since we'll assume it's four bytes, it
has to assign an address to each of those four bytes, so 'y[1]'
generates a meaningful address, but I don't see anything that says the
assignment has to word -- in fact, it seems to me that the alignment
rules allow it to fail. That byte has to have an address, but nothing
says we can use it. If we originally allocated the memory as an array of
char (or used malloc, etc.) then it's required to be aligned so we can
use it in this fashion -- but if we allocate it statically or
automatically for a non-char type, the access may be misaligned.
The second approach is to fundge it: read a whole 32-bit word (or
whatever) and carry out byte-level operations inside of the registers,
using bit masks, anding/oring, etc., to make the right things happen.
For example, your code above could be encoded something like:
loop:
sub r1, r1
mov r0, banner[r1]
and r0, 0xffffff00
and r0, 0xffff00ff
and r0, 0xff00ffff
and r0, 0x00ffffff
mov banner[r1], r0
cmp banner, 20
jne loop
Of course any decent compiler would figure out that the four consecutive
AND's set the whole thing to zero, and that it was never using the
previous value, so this would almost certainly end up just writing full-
words. A more interesting case would be something like:
char x[10];
x[1] += 2;
For this, the compiler would have to generate something like:
mov r0, x[0] // includes x[1]
mov r1, r0 // make a copy
and r1, 0x0000ff00 // isolate the addend
shr r1, 8 // shift it so that byte is a bottom of reg.
add r1, 2 // do the actual addition
and r0, 0xffff00ff // mask byte out of original word
shl r1, 8 // shift copy back where it belongs
or r0, r1 // or the result back into the original word
mov x[0], r0 // store the result, including 3 unchanged bytes
If x were declared volatile, however, this probably wouldn't conform
anymore, since it generates reads and writes of values that aren't
changed in the source code.