views:

177

answers:

5

Ok here's my problem. I want to loop through a simple char buffer using inline asm and VC++;

My agenda is to create a loop that reads information from memory as fast as physically possible

heres my code

char buffer[howmany];
memset(buffer,33,howmany);
char arr = 0;
__asm
{
MOV     eax,seg buffer ;operand size conflict
MOV     eds,eax
MOV ecx,[howmany]
MOV     ebx,ip
MOV     arr, ES::buffer[ecx] ;operand size conflict
                             ;inline assembler syntax error in 'third operand'
                             ;found 'bad token'
LOOP    ebx ;inline assembler syntax error in 'opcode'; found 'bad token'
                ; 'LOOP' : identifier is reserved word
}

I'm pretty new with assembly, but this seems right, but it doesn't work? I'm not sure why. Thanks in advance.

Final Solution

__asm
{
    LEA         esi, buffer
    MOV      ecx,howmany
    buf_loop:   
    mov         eax, [esi]
    inc         esi
    dec         ecx
    jnz         buf_loop
}
A: 

The line LOOP ebx looks suspect, aren't you supposed to specify a label to jump to?

label:
//some code
LOOP label

Also if you want to avoid looping, check out the

REP MOVS

and

REP STOS

instructions.

Andreas Brinck
i stored the memory location of the beginning of the array...MOV ebx,ip...so it loops back to that and grabs the next character
kelton52
@kelton52 it doesn't work like that, you can't use the value of a register as a label.
Andreas Brinck
tried it and it fails the same way.
kelton52
reguardless though, you can loop to a specific segement offset.
kelton52
+2  A: 

The loop instruction requires a target label (it uses relative jumps, and the assembler calculates the difference automatically), so something more like this:

char buffer[howmany];
memset(buffer,33,howmany);
char arr = 0;
__asm
{
MOV     eax, buffer ; buffer is a pointer, thus eax contains address
MOV     eds, eax
MOV     ecx, howmany ; You probably want the value of howmany, not address
buf_loop:
MOV     arr, [eax] ; segments are for 16bit DOS code, just dereference the array pointer in
INC     TYPE buffer ; Move to next element
LOOP    buf_loop
}
Daniel Bruce
that also fails
kelton52
reguardless though, you can loop to a specific segement offset.
kelton52
I tried to fix up your code as best I can, according to guesses what you're trying to accomplish. It had numerous flaws.
Daniel Bruce
A: 

Is this protected mode code? If so, don't mess with EDS.

The loop instruction must give a jump destination label. Loading ebx with ip (or eip) cannot be done as ip is not a proper operand.

wallyk
my buffer is large so I'm moving to the segment it resides in to do the work.
kelton52
If you are in flat address protected mode, the buffer is in the data segment. Loading EDS is an expensive instruction: don't do it unless absolute necessary. If the value really needs changing, be sure to set EDS back to what it was before when finished.
wallyk
+4  A: 

First, there is no EDS, only DS. Even in 32-bit mode, the segment registers remain 16 bits.

Second, unless you're working on an ancient system like a DOS extender, or something really unusual (a lot different from a typical desktop/server OS like Windows, Linux, OS/X, BSD, etc.) you shouldn't modify any segment registers in any case. Most current systems use a "flat" memory model, where the OS sets up all1 the segment registers with a base of 0 and a limit of the top of memory, so you never have any reason to modify any of them at all.

Unfortunately, while it's easy to say your code is wrong, it's a bit harder to say what would be right -- you haven't said enough about what you want to do. Right now, it looks like you're copying from a buffer, but each time through the loop you're overwriting the value you wrote in the last iteration, so you might as well just copy the last word and be done. For looping through the buffer to accomplish much, you'd want to copy it to a destination buffer of the same (or larger) size:

mov ecx, howmany
mov esi, offset FLAT:source
mov edi, offset FLAT:dest
rep movsd

As others have already pointed out, the operand for a loop instruction is a label, not a register. What they don't seem to have pointed out is that with modern CPUs (anything newer than the original Pentium) you usually want to avoid using the LOOP instruction at all. Just for the sake of argument, however, a loop to do the move like above would look like:

    mov ecx, howmany
    mov esi, offset FLAT:source
    mov edi, offset FLAT:dest
move_loop:
    lodsd
    stosd
    loop move_loop

For a modern CPU, it's usually better to use more, but simpler, instructions.

; same setup as above
move_loop:
    mov eax, [esi]
    mov [edi], eax
    inc esi
    inc edi
    dec ecx
    jnz move_loop

The other side of things is that in this case, it's unlikely to matter -- unless it all fits in cache, a block move like this will almost always be limited by the memory bandwidth -- moves don't get much faster, but to get the last little bit of improvement, you want to use SSE instructions/registers.

Edit: One last detail. VC++ (among others) won't let you define a label inside an _asm block, so if you need a label, you do something like:

_asm {
    mov ecx, howmany
    mov esi, offset FLAT:source
    mov edi, offset FLAT:dest
}

move_loop:

_asm {
    lodsd
    stosd
    loop move_loop
}

1Well, not all -- FS and possibly GS won't be this way, but CS, DS, ES and SS will be. You don't want to change any of them anyway (in fact, attempting to do so will normally just get your program shut down).

Jerry Coffin
vc did let me define a label inside the __asm block...Also, what is a better method than loop? As I said I'm pretty new to assembly, and it's hard to find information on assembly with anything newer than 16bit architecture.
kelton52
A: 

I don't have time to write it out, but using SSE2 registers you can read 16 bytes per loop. You will have to have a byte based loop first to align though (and after)

Marco van de Voort