Hi

I've just come across a strange (to me) error when assembling a piece of code using masm.  I'm trying to point to a character in a string (esi) by using a register (ecx) as an offset.  The use of an offset works when adding them, but when I attempt to subtract them, it fails to assemble.  Here is an example:


mov dl, byte ptr ;This works fine

mov dl, byte ptr ;<--The assembler fails on this instruction


Upon viewing a disassembly listing of the working code, I noticed that the first statement is rewritten as


mov dl, byte ptr


with the registers in the instructions swapped.  I imagine the problem in the second line lies somewhere with this conversion, seeing that the order of the registers would not make a difference to an addition, but it would affect a subtraction.

Is the second line considered illegal syntax for masm or for assembly in general?

Is there a way to reference a location relative to esi by subtracting a value as in the second instruction?
Posted on 2006-09-29 07:05:33 by Timbo
it is impossible by opcode specification.
you have to use neg ecx, then addition
Posted on 2006-09-29 07:11:59 by Shoo
Thanks Shoo.  Due to the way ollydbg displayed rewrote the instruction, I thought it might not be allowed but thanks for confirming it.  It also never occurred to do the negation then the addition so thanks for that little gem too.  The code was part of a string reversing routine and I was just looking for a shorter way of doing it.  It only ended up 1 byte longer (using dec ecx actually), but at least I learnt something :)
Posted on 2006-09-29 07:21:29 by Timbo
Just to add a subtle point to Shoo's post, there is no way you could use a negative sign between either way of addressing mode. You could form the effective address with the below formula

Segment address + Base address + Index multiplied by the scale + Displacement

Therefore, you are not allowed to compute the effective address of a memory location using the negative sign. Just like Shoo implied. Oh before i forget, if you are trying to navigate backwards through the elements of some kind of an array or something or generally in memory, you could decrement the base address or the index factor of the above formula N times where N is the number of bytes you need to navigate back through in each iteration.
Posted on 2006-09-29 08:52:50 by XCHG

if you are trying to navigate backwards through the elements of some kind of an array or something or generally in memory, you could decrement the base address or the index factor of the above formula N times where N is the number of bytes you need to navigate back through in each iteration.


Thanks for the formula!  In my implementation, I ended up decrementing the index.  I had esi pointing to the start of the string and edi pointing to the end of it.  By incrementing ecx as a displacement index, I could reference the characters at the start of the string by using ecx + esi, but unfortunately not for the characters at the end (by using the flawed edi - ecx).  I settled for a simple dec edi on every iteration.  I was basically trying to cheat and see if I could get away without using an extra instruction.
Posted on 2006-09-29 09:24:41 by Timbo
Here is a little procedure I wrote despite not having enough time to code it the way I like, however, it works, to show you how you could navigate back through characters and stuff using LEA. This procedure reverses a string without allocating space in the stack or using a local variable. It uses the string itself to reverse its content and it works like this.

Imagine you have the string "Assembly" which is 8 bytes long. First you have to find the end of the string and let one of the base register hold the address of the beginning of the string. Now for example, EBX points at the last byte in the string and ESI is at the beginning of the string. By subtracting the memory address of the ESI register from the EBX you will find the length of the string which is eight. Put this length in another register preferably the count register. Now what we do is that we move the first byte to the last and the last to the first, then we decrement the pointer to the last byte of the string by one and increment the pointer to the beginning of the string by one too.

Therefore, we first move A to Y and Y to A, and we'll have "YssemblA".
Then we have to continue doing this but for ECX/2 times because if we do this for ECX times we will get the original value back. Thus, you need to divide the value of the counter by 2 using the SHR instruction.

One important thing to notice is that not every string has an even length, for example, "Borland". The length of the string is 7 which if devided by 2 would result in three. But it is no big deal due to the fact that the character placed at the center does not need to get replaced or replace anything in a string with an odd length.

Below is a procedure I coded which does this for you.

Posted on 2006-09-29 13:50:00 by XCHG
Thanks XCHG.  That's pretty much the same code as I had for my own procedure, although I forgot to include any minimum length checking, so I'm glad I read your post!  Using the lea instruction is a good idea too, i'll use that one!
Posted on 2006-10-02 23:15:03 by Timbo