· Начало · Статистика · WASM.RU · Noir.Ru ·

 WASM Phorum (Оффлайн - 24.11.2003) —› WASM.ASSEMBLER —› Помогите перевести c++ код на асм

Посл.отвђт Сообщенiе


Дата: Апр 23, 2003 11:39:08

Вот
char LRC(char* buf){
char res = 0;
for (;*buf != ETX;)res ^= *buf++;
res ^= *buf++;
*buf = res;
return res;
}
я попробовал так, но может кто посоветует лучше?

MOV eax, 0
MOV ecx, 0
jm01:
MOV DL, Pin[ecx]
XOR AL,DL
INC ecx
CMP DL,3
JNE jm01
MOV Pin[ecx], AL
RET


Дата: Апр 23, 2003 12:17:13

mov ebx,buf ; или lea или mov offset
xor al,al ; res = 0

for_begin:

cmp byte ptr [ebx],ETX ; for (;*buf != ETX;)
jz for_end

xor al,byte ptr [ebx] ; res ^= *buf
inc ebx ; *buf++
jmp short for_begin

for_end:
xor al,byte ptr [ebx] ; res ^= *buf
inc ebx ; *buf++

mov [ebx],al ; *buf = res


Дата: Апр 23, 2003 12:25:27

Спасибо. :)


Дата: Апр 24, 2003 03:45:34

Еще забыл
[code]
mov buf,ebx ; чтобы учесть, что buf изменился
[/code]


Дата: Апр 26, 2003 00:00:15

P2M
Вы забыли push ebx / pop ebx

чтобы учесть, что buf изменился
Не надо учитывать - локальная переменная


Дата: Апр 26, 2003 03:41:15 · Поправил: boozook

Такой вариант должен быть лучше:

LRC proc uses edi pbuf:PCHAR
mov edi,pbuf
mov ah,[edi] ; первый(или последний) xor здесь
mov al,ETX
scasb ; ETX ?= *buf++
je endfor ; если == -> конец

startfor:
xor ah,[edi] ; res ^= *buf
scasb ; ETX ?= *buf++
jne startfor ; если != -> продолжаем

endfor:
mov al,ah
mov [edi],ah ; *buf = res
ret
LRC endp

...
start:
cld ; сбросить флаг направления
...
call LRC
...


Дата: Апр 26, 2003 11:05:02 · Поправил: P2M

boozook
Про push/pop спорить не буду, не обратил внимание, что надо оформить как функцию.
Можно заменить EBX на EDX/ECX, тогда можно без push/pop.

Не надо учитывать - локальная переменная
А вот это не обязательно, т.к. вызывающий код не показан.

Чтобы не быть голословным приведу _гипотетический_ пример.
[code]
.data
buf db '1234567890', 0

.code

; Ищет в заданной строке '5'
; Изменяет переданный адрес, так чтобы он указывал на '5' или конец строки
;
; Возвращает
; ноль - '5' не найдена
; не ноль - '5' найдена
fn1 PROC

mov edx,[esp+4]
xor eax,eax
mov al,'5'
@@:
cmp ah,[edx]
jz @F
cmp al,[edx]
jz @F
inc edx
jmp short @B
@@:
mov [esp+4],edx ; !!! сохранить
and al,[edx]

ret
fn1 ENDP

;
; MessageBox заданной строки
;
fn2 PROC

mov eax,[esp+4]
invoke MessageBox,0,eax,0,MB_OK

ret
fn2 ENDP

;
; Демонстрация использования одного параметра для двух функций.
;
main proc

push offset buf
call fn1
cmp al,'5'
jnz @F
call fn2
@@:
pop eax

ret
main endp
[/code]

Разумеется такой "оптимизации" не получится с макросами подобными INVOKE.


Ваш вариант кода безусловно имеет законченную форму, но я вижу в нем недостатки:
1) лишний SCASB;
2) CLD безопаснее делать внутри функции и добавить PUSHF/POPF;
3) afaik SCASB работает медленнее, чем пара CMP и INC.


Дата: Апр 26, 2003 15:22:19 · Поправил: boozook

P2M
А вот это не обязательно, т.к. вызывающий код не показан.
Это пример другой функции, и на asm'е. Не знаю возможно ли на Си сделать такую оптимизацию, но первоначальная процедура точно не предусматривает сохранения результата в стеке. Сишный компилятор может даже использовать это место под другую локальную переменную, после занесения значения buf в регистр.

1) лишний SCASB;
у меня цикл начинается со второй строки процедуры, метку надо было назвать start_repeat :)

2) CLD безопаснее делать внутри функции и добавить PUSHF/POPF;
Возможно. Скорее всего, по правилам - процедуры не обязаны сохранять этот флаг. Я точно не знаю. Но тогда зачем PUSHF/POPF?
;При низкоуровневой оптимизации, ее можно засунуть вместо ALING'a

3) afaik SCASB работает медленнее, чем пара CMP и INC.
Опять же не уверен, но по-моему процессоры начиная с PPro обрабатывают 3 инструкции за такт, при условиях их упорядочивания 4-1-1 и (почти обязательном)отсутствии переходов.

тогда:
scasb ;3mops
je endfor ;1 mop
xor ah,[edi] ;1 mop
, должны выполниться за один такт

Да, еще. Подозреваю, что макрос proc всегда генерит такую лажу:
push ebp
mov ebp,esp
...
leave

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

LRC proc ; pbuf:PCHAR
cld
xchg edi,[esp+4] ; будет быстрее если использовать: mov edx,edi; pop edi
mov ah,[edi] ; первый(или последний) xor здесь
mov al,ETX
scasb ; ETX ?= *buf++
je endfor ; если == -> конец

startfor:
;повторяем это много раз
xor ah,[edi] ; res ^= *buf
scasb ; ETX ?= *buf++
je endfor ; если == -> конец

xor ah,[edi] ; res ^= *buf
scasb ; ETX ?= *buf++
je endfor ; если == -> конец

xor ah,[edi] ; res ^= *buf
scasb ; ETX ?= *buf++
jne startfor ; если != -> продолжаем
endfor:
mov al,ah
mov [edi],ah ; *buf = res
pop edi ; или mov edi,edx
ret
LRC endp

Инструкции xchg, scasb и т.п.
Можно предположить, что Intel и AMD и далее будут совершенствовать свою продукцию, и тогда в следующих поколениях процессоров (а может и в P4) xchg и scasb уже не будут такими тормозными. Хотя в данном случае xchg находиться вне цикла, а использование scasb вроде как ускоряет процесс...


Дата: Апр 27, 2003 07:02:50

boozook
по-моему процессоры начиная с PPro обрабатывают 3 инструкции за такт
Таких тонкостей я учитываю.
Однако bcc v5.5 с опцией оптимизации по скорости и для PPro генерирует код с CMP + INC.
Надо было сразу предложить автору темы сгенерировать ASM-код при помощи Си'шного компилятора.

Про лишний SCASB я имел ввиду, что пару
scasb ; ETX ?= *buf++
je endfor ; если == -> конец
заменить на
jmp short @@_на_второй_scasb

Подозреваю, что макрос proc всегда генерит ...
Afaik если использовать расширения USES, LOCAL, параметры, указывать язык и соглашения по вызову, то да, иначе нет.


Дата: Апр 27, 2003 11:21:39

Можно ведь это скомпилить и дизассемблировать...


Дата: Апр 27, 2003 21:49:01 · Поправил: boozook

P2M
bcc v5.5 с опцией оптимизации по скорости и для PPro генерирует код с CMP + INC.
А он учитывает все тонкости архитектуры этих процессоров? Я не уверен. Если компилятор MSVC++ перевод числа с плавающей запятой в целое у меня скомпилировал так:
fld qword ptr [eax]
call _ftol ; функция из библиотеки MSVCRT32.DLL
;результат в eax

если использовать расширения USES, LOCAL, параметры, указывать язык и соглашения по вызову
я это и имел ввиду. Imho сложно написать такую процедуру, в которой все это необходимо. Если только в цикле что-нибудь в стэк загонять

spaces
Можно ведь это скомпилить и дизассемблировать...

[C] Агнер Фог, пер. Aquila

... рекомендуется, чтобы компилятор
умел переводить высокоуровневый код напрямую в ассемблер. Это даст вам гарантию, что вы получите верный метод вызова функции. Большинство компиляторов C++ умеют это делать
...
; int square (int x);
SQUARE_I PROC NEAR ; целочисленная функция вычисления квадратного корня
@square$qi LABEL NEAR ; имя, создаваемое компилятором Borland
?square@@YAHH@Z LABEL NEAR ; имя, создаваемое компилятором Microsoft
_square__Fi LABEL NEAR ; имя, создаваемое компилятором Gnu
PUBLIC @square$qi, ?square@@YAHH@Z, _square__Fi
MOV EAX, [ESP+4]
IMUL EAX
RET
SQUARE_I ENDP

; double square (double x);
SQUARE_D PROC NEAR ; функция вычисления квадратного корня с двойной точностью

@square$qd LABEL NEAR ; имя, создаваемое компилятором Borland
?square@@YANN@Z LABEL NEAR ; имя, создаваемое компилятором Microsoft
_square__Fd LABEL NEAR ; имя, создаваемое компилятором Gnu
PUBLIC @square$qd, ?square@@YANN@Z, _square__Fd
FLD QWORD PTR [ESP+4]
FMUL ST(0), ST(0)
RET
SQUARE_D ENDP

Хех, я лучше сам переведу :)


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.037