-
> Pavia © (01.06.16 16:41) [39]
Ну так это же настройки компилятора, а не отладчика :)
-
-
> Поэтому для него, не как у других инструкций.
ничего не понял, ты хочешь сказать что для других инструкций префикс 0x67 не используется, только для LOOP? :)
-
> ничего не понял, ты хочешь сказать что для других инструкций > префикс 0x67 не используется, только для LOOP? :)
Я хочу сказать, что у Loop'а ECX это не регистр, а адрес! Поэтому вместо db 66h надо использовать db 67h.
Обычные инструкции: "pop cx" "popd ecx" = "db 66h pop cx"
У лупа "loop cx" "loopd ecx" = "db 67h loop cx"
-
> > Я хочу сказать, что у Loop'а ECX это не регистр, а адрес! >
Не, там работает все немного по другому, 67 указывает что нужно сверятся с регистром CX, а 66 указывает что переход будет идти на младшую часть рассчитываемого адреса, к примеру:
66E2E5 loop $005b1fe4
здесь прыжок произойдет не на адрес 005b1fe4 а на адрес 00001fe4
-
> Потому что, по пунктам: > > 1. > > В начале > push ebp; > mov ebp,esp; > > и в конце: > > pop ebp; > ret $0008; > > > Это стековый фрейм, он добавляется автоматом при использовании > процедурой самого стека (под локальные переменные, под входные > параметры). > > 2. > > ret $0008 > > чистится стек из-за соглашения FASTCALL (в частности нивелируется > передача второго параметра через стек) > > 3. > > push ebx; > и в конце: > mov eax,ebx; > pop ebx; > > EBX обьектный регистр, который нужно сохранять, видя что > ты его используешь, компилер тебя подстраховывает >
Чего же тогда тут компилятор не хочет меня подстраховывать, и вообще не проявляет никакой самодеятельности? procedure rave;
asm
mov ebp,ecx
mov ebx,edx
end; Этот бред так и компилируется: mov ebp,ecx
mov ebx,edx
ret и больше ничего.
-
ну вот такой компилятор :)
-
А можно вкратце, раз уж тема зашла, какие еще регистры нужно сохранять? И в 64 битах.
-
> DayGaykin © (02.06.16 13:26) [47] > А можно вкратце, раз уж тема зашла, какие еще регистры нужно > сохранять? И в 64 битах.
32: EBX, EPB, ESP, EDI, ESI 64: RBX, RBP, RSP, RDI, RSI, R12-R15
-
Вот ради прикола попробовал написать такую функцию: function btc(var num:int64):byte;
asm
push eax
mov ecx,[eax]
mov al,-2
call @continue
pop ecx
mov ecx,[ecx+4]
@continue:
lea edx,[ecx-1]
inc al
or ecx,edx
jnz @continue
end; Компилятор на этот раз ничего от себя не добавил. В стеке ничего не передается. Поэтому в конце компилятор ставит просто ret Но эта штука почему-то виснет. И под отладчиком тоже виснет на call @continue Почему?
-
Мда. уже нашел где я протупил
-
jmp @@continue
@@continue:
-
> dmk © (02.06.16 20:10) [51] > > jmp @@continue > > @@continue:
Не. Call @continue - это было так задумано. Просто дальше получился бесконечный цикл, а отладчик видимо пошагово показывает результаты выполнения команд только то что до Call. А при Call похоже что шагом считает всю подпрограмму пока из нее не выйдет по ret Вот переписал так:
function btc(var num:int64):byte;
asm
push eax
mov ecx,[eax]
xor eax,eax
call @cnt32
pop ecx
mov ecx,[ecx+4]
@cnt32:
or ecx,ecx
jz @exit
@continue:
inc eax
lea edx,[ecx-1]
and ecx,edx
jnz @continue
@exit:
end;
Теперь работает.
-
Хмм, а не проще считать так? Зачем Вам цикл такой?
function NumBits(v: int64): int64; asm popcnt rax, v end;
procedure TForm3.ButtonClick(Sender: TObject); var v: int64; bc: int64;
begin v := 48756000; //Кол-во бит bc := NumBits(v); ShowMessage('Кол-во бит в числе ' + IntToStr(v) + ' = ' + IntToStr(bc)); end;
-
> dmk © (02.06.16 23:12) [53] > > Зачем Вам цикл такой? >
1. В [52] просто интересно было как отнесется компилятор к дерганию процедурой\функцией своего же хвоста. Хотя можно обойтись (и даже быстрее было бы) без этого. 2. метод [52] далеко не самый лучший, но он не так уж и плох в случаях, когда приходится обрабатывать большое кол-во данных, где заранее известно, что среднее количество единичных бит в числе не большое. Например 5-8. 3.
> Хмм, а не проще считать так? > function NumBits(v: int64): int64; > asm > popcnt rax, v > end;
И как будет работать такая функция, если вдруг процессор не поддерживает SSE4?
-
Пишите функции-переменные с пометкой overload. При инициализации проверяете на поддержку и грузите нужную переменную. Вашу старую или SSE4.2
type TNumBits = function(v: uint64): byte;
var NumBits: TNumBits;
//Bit20 A value of 1 indicates that the processor supports SSE4.2 function CPU_SupportSSE42: boolean; asm mov rax, $01 cpuid xor rax, rax //result := false test ecx, 00100000h //тестируем 20-й бит jz @NOSSE42 inc rax //result := true @NOSSE42: end;
SSE42 Давно уже существует. Большинство современных процессоров этот набор поддерживает. У Intel начиная с Core2DUO, Core2QUAD; У AMD только начиная с Buldozer FX.
-
> dmk © (03.06.16 12:47) [55]
тогда уж:
function CPU_SupportSSE42: Boolean; asm mov eax, 1 cpuid test ecx, 00100000h setne al end;
-
У меня получилось так:
function NumBitsX86(v: uint64): byte;
asm
mov rdx, v
bswap rdx
mov rcx, 64
xor rax, rax
@@NB:
xor r8b, r8b
shld r8, rdx, 1
shl rdx, 1
add al, r8b
dec rcx
jnz @@NB
end;
function NumBitsSSE42(v: uint64): byte;
asm
popcnt rax, v
end;
Initialization
if CPU_SupportSSE42 then
NumBits := NumBitsSSE42 else
NumBits := NumBitsX86;
-
Rouse_ © (03.06.16 13:06) [56]
Спасибо! Будем знать ;)
-
Кстати, в какой версии Delphi встроенный ассемблер поддерживает мнемоники SSE4.2?
|