встроенный буферный цикл asm - PullRequest
0 голосов
/ 19 декабря 2009

Хорошо, вот моя проблема. Я хочу перебрать простой буфер, используя встроенный asm и VC ++;

Моя задача - создать цикл, который считывает информацию из памяти настолько быстро, насколько это возможно физически

вот мой код

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
}

Я довольно новичок в сборке, но это кажется правильным, но это не работает? Я не уверен почему. Заранее спасибо.

Окончательное решение

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

Ответы [ 5 ]

4 голосов
/ 19 декабря 2009

Во-первых, нет ЭЦП, только DS. Даже в 32-битном режиме регистры сегментов остаются 16 битами.

Во-вторых, если вы не работаете с древней системой, такой как расширитель DOS, или чем-то действительно необычным (сильно отличающимся от типичной настольной / серверной ОС, такой как Windows, Linux, OS / X, BSD и т. Д.), Вам не следует Не изменяйте регистры сегмента в любом случае. В большинстве современных систем используется «плоская» модель памяти, где ОС устанавливает все 1 регистры сегмента с основанием 0 и пределом верхней части памяти, поэтому у вас никогда не будет причин изменять какие-либо из них вообще.

К сожалению, хотя легко сказать, что ваш код неверен, немного сложнее сказать, что будет правильно - вы недостаточно сказали о том, что вы хотите сделать. Прямо сейчас, похоже, что вы копируете из буфера, но каждый раз в цикле вы перезаписываете значение, которое вы записали в последней итерации, так что вы можете просто скопировать последнее слово и все готово. Чтобы выполнить цикл через буфер, чтобы добиться многого, вам нужно скопировать его в буфер назначения того же (или большего) размера:

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

Как уже отмечали другие, операндом для инструкции цикла является метка, а не регистр. Кажется, что они не указали на то, что с современными процессорами (чем-то более новым, чем оригинальный Pentium) вы обычно хотите вообще избегать использования инструкции LOOP. Однако, ради аргумента, цикл для перемещения, как указано выше, будет выглядеть так:

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

Для современного процессора обычно лучше использовать больше, но более простых инструкций.

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

Другая сторона в том, что в этом случае это вряд ли имеет значение - если все это не помещается в кэш, перемещение блока, подобное этому, почти всегда будет ограничено пропускной способностью памяти - перемещения не получаются намного быстрее, но чтобы получить последнее улучшение, вы хотите использовать инструкции / регистры SSE.

Редактировать: Последняя деталь. VC ++ (помимо прочего) не позволит вам определить метку внутри блока _asm, поэтому, если вам нужна метка, вы делаете что-то вроде:

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

move_loop:

_asm {
    lodsd
    stosd
    loop move_loop
}

1 Ну, не все - FS и, возможно, GS не будут такими, но CS, DS, ES и SS будут. В любом случае, вы не хотите менять ни одну из них (на самом деле, попытка сделать это обычно приводит к закрытию вашей программы).

2 голосов
/ 19 декабря 2009

Инструкция цикла требует целевой метки (она использует относительные переходы, и ассемблер автоматически вычисляет разницу), поэтому что-то вроде этого:

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
}
0 голосов
/ 20 декабря 2009

У меня нет времени, чтобы записать его, но используя регистры SSE2, вы можете прочитать 16 байтов за цикл. Сначала вам нужно будет иметь байтовый цикл, чтобы выровнять хотя (и после)

0 голосов
/ 19 декабря 2009

Это код защищенного режима?Если это так, не связывайтесь с EDS.

Инструкция цикла должна давать метку назначения перехода.Загрузка ebx с ip (или eip) не может быть выполнена, поскольку ip не является правильным операндом.

0 голосов
/ 19 декабря 2009

Строка LOOP ebx выглядит подозрительно, разве вы не должны указывать метку для перехода?

label:
//some code
LOOP label

Также, если вы хотите избежать зацикливания, проверьте

REP MOVS

и

REP STOS

инструкции.

...