Suppose we have an array of 100 numbers. I saw a question about this here but didn't understand how to solve the problem. These are the instructions we have:
Instruction | Meaning |
---|---|
mov addr1,addr2 | Maddr1 = (Maddr2); |
mov addr1,(addr2) | Maddr1 = (M_(Maddr2)); |
mov (addr1),addr2 | M_(Maddr1) = (Maddr2); |
add addr1,addr2 | Maddr1 = (Maddr1) + (Maddr2); |
sub addr1,addr2 | Maddr1 = (Maddr1) - (Maddr2); |
add addr1,(addr2) | Maddr1 = (Maddr1) + (M_(Maddr2)); |
sub addr1,(addr2) | Maddr1 = (Maddr1) - (M_(Maddr2)); |
jnz addr1,addr2 | if (Maddr1)≠0 then PC = addr2; |
jz addr1,addr2 | if (Maddr1)=0 then PC = addr2; |
jneg addr1,addr2 | if (Maddr1)<0 then PC = addr2; |
jpos addr1,addr2 | if (Maddr1)>0 then PC = addr2; |
And this is the code to solve the program using indirect addressing:
org 100h
loop:
add sum,(arrptr)
add arrptr,two
sub count,two
jnz count,loop
arrptr: dw array
sum: dw 0
count: dw 200
two: dw 2
array: dw 100 dup(?)
I wanted to know how to sum these elements without using <arrptr>. I know it will be a self modifying code but don't know exactly how to write this code.
I was looking for a way to move every element to the address of the first element of the array but didn't find a way.
Instead of moving the address of elements (in short, we can't do this), we modify the instruction to access successive elements at their sequential addresses.
To do self modifying code, we write an instruction to access the first element, run it, then increment the code instruction itself, in such a way that the instruction now points to the next element.
In pseudo code:
On the very first iteration, the
add sum,array
will fetch the first element of the array. During the loop body, this instruction itself is incremented so that for the second iteration that instruction now reads (in machine code and to the processor) asadd sum,array+2
.Issues:
This won't work on modern architectures with caches unless you also use cache flushing operations (which would make it very slow).
Much like with global variables, the instruction at
Loop:
is modified during the execution of the loop, meaning this loop as a whole, in order to run the whole loop again, we would have to reset the instruction atLoop:
back to refer to the beginning.The same is true for programs that rely on the initialization of mutable global variables — the parts of the program that rely on this global initialization will require re-initialization if that section of code is to be reused.
The amount to increment depends on the size of the array elements. For example, for an 8-bit integer, we would add 1 instead of 2.
Instruction Set Encoding Issues
On some architectures the encoding of the
add
will use a straightforward immediate value for which a simple increment of the whole machine code instruction as an integer word makes sense.However, on some architectures, an immediate of 0 is not encoded, thus with a naïve approach there could be no immediate to increment.
On other architectures, the bits of immediates are distributed throughout the instruction and not necessarily consecutive making a simple increment of the immediate value difficult.
Other problems include the immediate not being large enough to accommodate the indexing to elements far further in the array.
And further, we should know the size of the instruction being incremented.