I am barely learning x86 assembly, and I am having trouble.
How do I address the individual items in an array in assembly?

This is my attempt, but I am very confused.

char example( char arrayOfLetters[], int arraySize) // arrayOfLetters = {a, B, c, D, e, F}
{
    ~asm{
        mov dl, btye ptr arrayOfLetters[0]   // eax[1], eax[2], ......?
        }
}

Thanks.

Recommended Answers

All 4 Replies

Im writing in x86, in C

Seems like that works, but when I try to move the char into the register DL, DL becomes a random char and not the one i tried to move.

It would be arrayOfLetters+0 for the first char and arrayOfLetters+1 for the second (and so on...).

Why are you coding this through C? It might be easier if you downloaded a compiler like A86 available as shareware.

You have some homework to do!

For sequential access, read up on the LODS and STOS instructions. There is a byte specific form of each. For the LODSB, put the array pointer in ESI (SI if 16-bit), use CLD to clear the direction flag then with each execution of LODS, the next byte in the array will be loaded into AL. (The string instructions assume that data is located in DS.) STOSB is similar, but stores AL to memory instead (and uses DI, not SI). There are several other string instructions and all are quite handy:

MOVSB: Moves bytes from DS:SI to ES:DI
SCASB: Scan string at ES:DI for a value specified in AL

Note that there are Byte, Word and DWord forms of these instructions and all will take the REP prefixes.

For Random access, read up on the various address modes for the MOV instruction. For example you can load your address pointer into a base register (BP or BX) and the array index into an index register (SI or DI) and execute the appropriate MOV instructrion - such as:

MOV AL,[BX+SI]

If you are accessing memory whose address is known at compile time, you can include the offset to the memory right in the instruction and skip the use of the base register altogether:

MOV AL,SomeMemoryPlace[SI]

If this is Word or DWord access, then don't use AL, use AX, EAX, etc. The compiler will know what machine instruction to use based on the register size you specify and the correct number of bytes will be moved. But YOU will need to make sure that the index is properly updated for the correct number of bytes per item before each access. In 32 bit mode, you have a lot more flexibility about which registers you can use, plus a very nice feature of having indexes which automatically take care of scaling for word length.

I have assumed X86 instruction sets. If you are using something else, the details change but the concepts are the same. Now, you have some reading and experimenting to do. Happy programming!

Here's another thing I just noticed. This code line:

mov dl, btye ptr arrayOfLetters[0]

is not legal assembler code. This is for 2 reasons. First, there is no X86 instruction that allows an implied index (that is , the [0]). It will simply compile with a fixed offset and if you try to use a variable instead of a numeric constant (i.e., mov dl, btye ptr arrayOfLetters[k]) you will get an error. In fact, I'm astonished that you didn't get an error already, since "0" is not a legal register name. It's possible that the compiler is loading zero into an implied register behind the scenes and uisng that on your behalf while not troubling you about the error. Nevertheless, a true index MUST be one of the index registers. Second, the declaration of arrayOfLetters does not indicate where the array is located. If it is a static declaration (i.e., defined at compile time), then the array will be at a known, fixed location in the DataSegment and you can do something like this:

mov si, index                   //Index of desired item
mov dl, arrayOfLetters[si]      //get item

On the otherhand, if it's a dynamic allocation, things get a little more complicated. Allocations on the stack should be accessible using BP since all C routines will have established a stack frame which has already put the Stack pointer in BP and allocated local storage for just this purpose. Then you need something like this:

mov si, index                   //Index of desired item
mov dl, arrayOfLetters[bp+si]   //get item

This gets the byte from the stack, offset by arrayOfLetters from BP+SI. (Note that in this case, arrayOfLetters represents an offset in the stack frame to the allocated array, NOT it's address!). If you have no stack frame, it's still possible to access it, but you're on your own. Finally, if arrayOfLetters is on the heap (or TLS, etc.), then you need to load it's address into a base register. You cannot use an instruction with the base address compiled in because the address is not known at compile time. You might try something like this:

lea bx, arrayOfLetters
mov si, index
mov dl,[bx+si]

But, unless C/C++ is doing some behind the scenes work on your behalf, the "lea" will probably not work. You will most likley have to declare a pointer variable and load it with the arrayOf Letters address. Then in assembly code you can:

mov bx, pointerToArray

You will probably also want to use 32 bit registers (EBX and ESI). In pure assembler, you would call the memory allocator which returns the pointer directly. This is what you would put into bx. Note that the "byte ptr" directive is optional in this case because the use of "dl" as the destination will tell the assembler that you are fetching bytes, and pointers are always the implied type in base registers. Nevertheless, it is possible that an asm{} block in some C/c++ compilers may require it, and some people always specify operand sizes explicitly for reasons of code clarity.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.