Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2017.08.27;
Скачать: [xml.tar.bz2];

Вниз

Передача параметров функции   Найти похожие ветки 

 
Rouse_ ©   (2016-06-01 16:59) [40]


> Pavia ©   (01.06.16 16:41) [39]

Ну так это же настройки компилятора, а не отладчика :)


 
Pavia ©   (2016-06-01 16:59) [41]


> > Код можно принудительно переключить приставкой.
> > Обычно db 66h, но для Loop db 67h
>
>
> не верно, префикс 0х66 т.н. OperandSizeOverride используется
> для модификации инструкции (insw->insd/iret->iretd и т.п.
> ) а для модификации регистров используется префикс AddressSizeOverride
> = $67

Тут ты ошибаешься. Смотри маны. Loop относится к группе строковых инструкций. Поэтому для него, не как у других инструкций.
Смотри маны:
https://docviewer.yandex.ru/?url=ya-disk-public%3A%2F%2Fks8F6OS9JWdJWsURii23TBL%2F3QETut6hh5lPpMKMQfE%3D&name=253666.pdf&page=644&c=574ee91d863a


IF (AddressSize = 32)
   THEN Count is ECX;
ELSE IF (AddressSize = 64)
   Count is RCX;
ELSE Count is CX;
FI;


 
Rouse_ ©   (2016-06-01 17:08) [42]


> Поэтому для него, не как у других инструкций.

ничего не понял, ты хочешь сказать что для других инструкций префикс 0x67 не используется, только для LOOP? :)


 
Pavia ©   (2016-06-01 17:15) [43]


> ничего не понял, ты хочешь сказать что для других инструкций
> префикс 0x67 не используется, только для LOOP? :)

Я хочу сказать, что у Loop"а ECX это не регистр, а адрес!
Поэтому вместо db 66h надо использовать db 67h.

Обычные инструкции:
"pop cx"
"popd ecx" = "db 66h pop cx"

У лупа
"loop cx"
"loopd ecx" = "db 67h loop cx"


 
Rouse_ ©   (2016-06-01 17:30) [44]


>
> Я хочу сказать, что у Loop"а ECX это не регистр, а адрес!
>

Не, там работает все немного по другому, 67 указывает что нужно сверятся с регистром CX, а 66 указывает что переход будет идти на младшую часть рассчитываемого адреса, к примеру:

66E2E5         loop $005b1fe4

здесь прыжок произойдет не на адрес 005b1fe4 а на адрес 00001fe4


 
SergP ©   (2016-06-02 13:07) [45]


> Потому что, по пунктам:
>
> 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

и больше ничего.


 
Rouse_ ©   (2016-06-02 13:19) [46]

ну вот такой компилятор :)


 
DayGaykin ©   (2016-06-02 13:26) [47]

А можно вкратце, раз уж тема зашла, какие еще регистры нужно сохранять? И в 64 битах.


 
Rouse_ ©   (2016-06-02 15:44) [48]


> DayGaykin ©   (02.06.16 13:26) [47]
> А можно вкратце, раз уж тема зашла, какие еще регистры нужно
> сохранять? И в 64 битах.

32: EBX, EPB, ESP, EDI, ESI
64: RBX, RBP, RSP, RDI, RSI, R12-R15


 
SergP ©   (2016-06-02 16:15) [49]

Вот ради прикола попробовал написать такую функцию:

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
Почему?


 
SergP ©   (2016-06-02 16:28) [50]

Мда. уже нашел где я протупил


 
dmk ©   (2016-06-02 20:10) [51]

jmp @@continue

@@continue:


 
SergP ©   (2016-06-02 21:08) [52]


> dmk ©   (02.06.16 20:10) [51]
>
> jmp @@continue
>
> @@continue:


Не. Call @continue - это было так задумано.
Просто дальше получился бесконечный цикл, а отладчик видимо пошагово показывает результаты выполнения команд только то что до Call. А при Call похоже что шагом считает всю подпрограмму пока из нее не выйдет по ret

Вот переписал так:
// Вычисление кол-ва единичных бит в 64-разрядном числе, для случаев
// когда среднестатистическое их количество невелико.
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;


Теперь работает.


 
dmk ©   (2016-06-02 23:12) [53]

Хмм, а не проще считать так?
Зачем Вам цикл такой?

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;


 
SergP ©   (2016-06-03 03:52) [54]


> 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?


 
dmk ©   (2016-06-03 12:47) [55]

Пишите функции-переменные с пометкой 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.


 
Rouse_ ©   (2016-06-03 13:06) [56]


> dmk ©   (03.06.16 12:47) [55]

тогда уж:
function CPU_SupportSSE42: Boolean;
asm
 mov eax, 1
 cpuid
 test ecx, 00100000h
 setne al
end;


 
dmk ©   (2016-06-03 13:44) [57]

У меня получилось так:


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;



 
dmk ©   (2016-06-03 13:44) [58]

Rouse_ ©   (03.06.16 13:06) [56]

Спасибо! Будем знать ;)


 
SergP ©   (2016-06-03 13:49) [59]

Кстати, в какой версии Delphi встроенный ассемблер поддерживает мнемоники SSE4.2?


 
dmk ©   (2016-06-03 13:53) [60]

>SergP ©   (03.06.16 13:49) [59]
Delphi 2010 and XE support up to the SSE4.2 instruction sets


 
dmk ©   (2016-06-03 13:59) [61]

Rouse_ ©   (03.06.16 13:06) [56]
А как пользоваться SintaxHighlighter ? Не пойму никак )


 
NoUser ©   (2016-06-03 15:08) [62]

> dmk ©   (03.06.16 13:59) [61]
кнопочка "D" ))

Rouse_ , коль пошла такая пьянка, расскажи о выравнивании стека перед CALL -
как правильно, нужно/не нужно, насколько критично, сколько резервировать для регистровых параметров, сразу 20h или ?
Спасибо.


 
Rouse_ ©   (2016-06-03 15:23) [63]


> NoUser ©   (03.06.16 15:08) [62]

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


> Вызывающая функция отвечает за выделение пространства для
> параметров вызываемой функции и должна всегда выделять достаточное
> пространство для 4 параметров, даже если вызываемая функция
> не содержит такого количества параметров. Это помогает упростить
> поддержку функций без прототипов и функций с переменным
> количеством аргументов (vararg) C/C++. Для функций с переменным
> количеством аргументов или для функций без прототипов любое
> значение типа float должно быть продублировано в соответствующем
> регистре общего назначения. Любые параметры, следующие после
> первых 4, до вызова должны сохраняться в стеке над резервным
> хранилищем для первых четырех. Сведения о функции с переменным
> количеством аргументов представлены в разделе Функции с
> переменным количеством аргументов (Varargs). Сведения о
> функции без прототипов представлены в разделе Функции без
> прототипа.
> Выравнивание
>
> Большинство структур выровнены естественным выравниванием.
>  Главными исключениями являются указатели стека и функции
> распределения памяти malloc или alloca, которые выровнены
> на 16 байт для сохранения производительности. Выравнивание
> свыше 16 байт должно выполняться вручную, но начиная с 16
> байт выполняется общее выравнивание размера для операций
> XMM, которого должно хватать для большей части кода. Дополнительные
> сведения о структуре и выравнивании см. в разделе Типы и
> хранилище. Дополнительные сведения о стеке см. в разделе
> Использование стека.


 
SergP ©   (2016-06-03 16:08) [64]

Ну и тогда еще несколько вопросов:
Если допустим я захочу полностью переписать процедуру/функцию на ассемблере:
1. Как работать с глобальными переменными?
2. Как функция должна возвращать результат, если например это запись?
3. Если мне понадобится память для локальных переменных: как лучше делать:
не описывать переменные в секуии var, а просто уменьшать указатель стека на нужную величину, использовать этот кусок памяти, а перед выходом возвращать указатель стека в исходное состояние? или как-то по другому?
4. Если у меня WinXP, то использовать 64-битные РОН (rax, rbx....) я не могу?


 
dmk ©   (2016-06-03 16:36) [65]

1. mov rax, GlobalVar
2.

TSomeType = record
 private
 public
   function InRangeX(x: integer): boolean;
 end;


3. Как нравится.
4. Можешь, только передачу параметров свою делать надо. Например, через указатель.


 
Rouse_ ©   (2016-06-03 16:40) [66]


> Как работать с глобальными переменными?

как обычно. вместо:
MyGlobalVar := 123
пиши

lea eax, MyGlobalVar
mov [eax], 123



> Как функция должна возвращать результат, если например это
> запись?

структуры возвращаются по ссылке


> 3. Если мне понадобится память для локальных переменных:

лучше объяви их в секции var, компилятор сам добавит код под выделение памяти


> 4. Если у меня WinXP, то использовать 64-битные РОН (rax,
>  rbx....) я не могу?

регистры RAX и т.п. ты можешь использовать только в 64 битном коде, соответственно только под 64 битной ОС


 
dmk ©   (2016-06-03 18:26) [67]

>регистры RAX и т.п. ты можешь использовать только в 64 битном коде, соответственно
>только под 64 битной ОС

Странно, mmx разве не относится к 64 битам? В D7 раньше байт коды были. Использовал в 32 битном коде.


 
Rouse_ ©   (2016-06-03 19:41) [68]

Это разные вещи


 
SergP ©   (2016-06-04 09:56) [69]


> > Как функция должна возвращать результат, если например
> это
> > запись?
>
> структуры возвращаются по ссылке


А где выделяется память под это дело? И кто ее выделяет?
Вызываемая функция или вызывающая процедура/функция?
Т.е. Кто кому передает эту ссылку?


 
Игорь Шевченко ©   (2016-06-04 10:35) [70]

SergP ©   (03.06.16 16:08) [64]


> Ну и тогда еще несколько вопросов:


Рано тебе их задавать. Матчасть надо учить и не по форумам.


 
Inovet ©   (2016-06-04 12:10) [71]

> [64] SergP ©   (03.06.16 16:08)

Сделай для эксперимента на ASM и приликуй к основному модулю - это поубавит вопросов.


 
Inovet ©   (2016-06-04 12:12) [72]

Правильно. Самостоятельно это сделай.


 
SergP ©   (2016-06-04 13:25) [73]


> Inovet ©   (04.06.16 12:12) [72]
>
> Правильно. Самостоятельно это сделай.


С тем, что меня интересовало уже разобрался.

Но вот просто разбираться приходится по коду в окне CPU-View, а там читабельность низкая, навигация неудобная, да и самая большая проблема в том, что это все нельзя сбросить в текстовый файл.

Ну и кроме того там полно откровенного бреда. Конечно, когда пытаешься мыслить с точки зрения компилятора, то вроде понятно почему он сделал так. Но с точки зрения человека это бред...

Вот, например, один из перлов компилятора:
 ...if (num and 1) <>0 then
 mov eax,[ebp+$08]
 mov edx,[ebp+$0c]
 and eax,$00000001
 xor edx,edx
 cmp edx,$00
 jnz +$03
 cmp eax,$00
 jz +$06


 
Inovet ©   (2016-06-04 18:59) [74]

> [73] SergP ©   (04.06.16 13:25)
> да и самая большая проблема в том, что это все нельзя сбросить
> в текстовый файл.

Для этого есть реверсинженеринговые штуки, наподобие дизассемблеров.


 
Inovet ©   (2016-06-04 19:15) [75]

> [73] SergP ©   (04.06.16 13:25)
> Вот, например, один из перлов компилятора:

Ну это может быть в дебаг сборке такое?


 
Inovet ©   (2016-06-04 19:18) [76]

> [74] Inovet ©   (04.06.16 18:59)
> реверсинженеринговые

Да, на всякий случай, в Си есть опция компилятора, при включении которой, компилятор сначала в текстовый АСМ генерит, потм уже Амсом компилит.


 
Inovet ©   (2016-06-05 00:28) [77]

Розыч, неужели и ты заразился словом "прыжок"? Ну плохо оно звучит для русского слуха. Есть же нормальное слово "переход". Прыжок, млин. Я, может быть, на соответствующих тематческих форумах не бываю, но осуждаю. Какой нафиг прыжок.

Подпишусь - Ваш Граммар Наци. Давайте не будем использовать настолько тупые кальки.


 
Германн ©   (2016-06-05 01:37) [78]


> Игорь Шевченко ©   (04.06.16 10:35) [70]
>
> SergP ©   (03.06.16 16:08) [64]
>
>
> > Ну и тогда еще несколько вопросов:
>
>
> Рано тебе их задавать. Матчасть надо учить и не по форумам.
>

Вот какой смысл у этого поста?


 
Crysis ©   (2016-06-05 08:21) [79]

> первый параметр, как я понимаю передается через EAX
> Результат тоже вроде через EAX передается.
> Третий похоже через EDX
> А что со вторым?


Int64 передаётся через стек

> push ebp;    // Зачем делать то, что я не просил?
> mov ebp,esp;
> push ebx;
> pop ebp;
> ret $0008; //что за параметр?


Это особенность компилятора Delphi. Если есть стековые переменные в функции или секции var - Delphi делает префикс/постфикс и обращается к переменным через ebp. Если объявишь keyword через var - то указатель на него передастся через EDX, а третий параметр будет ECX.


 
Игорь Шевченко ©   (2016-06-05 10:28) [80]


> Ну и кроме того там полно откровенного бреда. Конечно, когда
> пытаешься мыслить с точки зрения компилятора, то вроде понятно
> почему он сделал так. Но с точки зрения человека это бред.
> ..


С точки зрения необразованного человека.



Страницы: 1 2 3 вся ветка

Форум: "Прочее";
Текущий архив: 2017.08.27;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.63 MB
Время: 0.004 c
3-1314713126
tomkat
2011-08-30 18:05
2017.08.27
Экранировать % в FireBird


2-1426143698
Atamali Memmedov
2015-03-12 10:01
2017.08.27
Exception


15-1464608311
SergP
2016-05-30 14:38
2017.08.27
Передача параметров функции


4-1283494887
worldmen
2010-09-03 10:21
2017.08.27
Определение существования окна


1-1352975235
yurikon
2012-11-15 14:27
2017.08.27
Доступ к массиву по ключу





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский