powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Умножение в ASM для x64-сборки
11 сообщений из 11, страница 1 из 1
Умножение в ASM для x64-сборки
    #39129089
kopiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем добрый день,

не подскажите, как изменить код:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
// Multiply big integers:
function __Mul(a, b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD
asm
 {$IFDEF WIN64}
  // ???
 {$ELSE}
  mul edx
  mov [ecx],edx
 {$ENDIF}
end;


чтобы он не выдавал ошибки в случае x64-сборки (First chance exception at $0000000000431B82. Exception class $C0000005 with message 'c0000005 ACCESS_VIOLATION'.)

ЗС
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129103
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И при чем тут умножение ?
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129105
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
И я бы даже спросил "и причем тут asm?"
Дабы приведенный код явно не ассемблер, а скорее что-то паскале-подобное.
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129119
kopiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Возможно, могу добавить только, что проблема в строке mov [ecx],edx , само умножение mul edx по крайней мере не выдает исключения. Директивы компилятора просто забыл удалить, извиняюсь.
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129132
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я добрый:

Тынц
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Procedures_and_Functions#Calling_Conventions

Тынц
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Using_Inline_Assembly_Code

32-bit

In general, the rules of register use in an asm statement are the same as those of an external procedure or function. An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers, but can freely modify the EAX, ECX, and EDX registers. On entry to an asm statement, EBP points to the current stack frame and ESP points to the top of the stack. Except for ESP and EBP, an asm statement can assume nothing about register contents on entry to the statement.

64-bit

In line with the x64 Application Binary Interface (ABI), the contents of the following registers must be preserved and restored within inline assembly functions: R12, R13, R14, R15, RDI, RSI, RBX, RBP, RSP, XMM4, XMM5, XMM6, XMM7, XMM8, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, and XMM15.

The first four parameters to inline assembler functions are passed via RCX, RDX, R8, and R9 respectively, except for floating-point arguments which use XMMO, XMM1, XMM2, XMM3. The math coprocessor is not normally used from x64 code. Registers used for function parameters can be modified freely.
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129135
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kopievВозможно, могу добавить только, что проблема в строке mov [ecx],edx , само умножение mul edx по крайней мере не выдает исключения. Директивы компилятора просто забыл удалить, извиняюсь.

Правильный ответ заключается в двух словах "calling_conventions". Что это такое - ты должен знать.

Выданных мною ссылок достаточно?

Не понимаю, какой смысл в такой сложной конструкции. Чем просто a*b не подошло? Да и я бы сказал, писать in line assembler и явно не указать calling_conventions это на мой взгляд дурной тон. Я сильно тупил, когда такой код увидел без явного указания register calling conventions ))). Я конечно понимаю, что он по умолчанию такой, но вдруг кто умолчания в компиляторе изменит... и все... в общем, дурной тон IMHO
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129236
kopiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Написал такую вещь:
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
function __Mul(a, b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD
{$IFDEF WIN64}
 var
  aux_hi, aux_lo : UInt64;
 begin
  aux_lo := UInt64(a) * UInt64(b);
  aux_hi := aux_lo shr 32;
  aux_lo := aux_lo - aux_hi shl 32;
  HiDWORD := DWORD(aux_hi);
  Result := DWORD(aux_lo);
{$ELSE}
 asm
  mul edx
  mov [ecx],edx
{$ENDIF}
end;


Конечно не гениально, но работает. Дизассемблирование не помогло, для этой же функции, например (х64):
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
myproject.pas.61: begin
0000000000431B80 55               push rbp
0000000000431B81 4883EC20         sub rsp,$20
0000000000431B85 488BEC           mov rbp,rsp
0000000000431B88 894D30           mov [rbp+$30],ecx
0000000000431B8B 895538           mov [rbp+$38],edx
0000000000431B8E 4C894540         mov [rbp+$40],r8
myproject.pas.62: aux_lo := UInt64(a) * UInt64(b);
0000000000431B92 8B4530           mov eax,[rbp+$30]
0000000000431B95 8B4D38           mov ecx,[rbp+$38]
0000000000431B98 480FAFC1         imul rax,rcx
0000000000431B9C 48894508         mov [rbp+$08],rax
myproject.pas.63: aux_hi := aux_lo shr 32;
0000000000431BA0 488B4508         mov rax,[rbp+$08]
0000000000431BA4 48C1E820         shr rax,$20
0000000000431BA8 48894510         mov [rbp+$10],rax
myproject.pas.64: aux_lo := aux_lo - aux_hi shl 32;
0000000000431BAC 488B4510         mov rax,[rbp+$10]
0000000000431BB0 48C1E020         shl rax,$20
0000000000431BB4 48294508         sub [rbp+$08],rax
myproject.pas.65: HiDWORD := DWORD(aux_hi);
0000000000431BB8 488B4540         mov rax,[rbp+$40]
0000000000431BBC 8B4D10           mov ecx,[rbp+$10]
0000000000431BBF 8908             mov [rax],ecx
myproject.pas.66: Result := DWORD(aux_lo);
0000000000431BC1 8B4508           mov eax,[rbp+$08]
0000000000431BC4 89451C           mov [rbp+$1c],eax
myproject.pas.76: end;
0000000000431BC7 8B451C           mov eax,[rbp+$1c]
0000000000431BCA 488D6520         lea rsp,[rbp+$20]
0000000000431BCE 5D               pop rbp
0000000000431BCF C3               ret
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129294
kopiev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Исключение происходило внутри функции, то есть возможно, что все дело в других регистрах в случае х64 после mul :
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function __Mul(a, b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD
asm
{$IFDEF WIN64}
  mul eax
  mov [???],eax
{$ELSE}
  mul edx
  mov [ecx],edx
{$ENDIF}
end;
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129316
kealon(Ruslan)
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kopiev,

тебе же уже Leonid Kudryavtsev сказал ответ
копай "calling_conventions", в win64 она всего одна должна применяться,
PS: а вообще регистр адреса 64-битный, это rcx
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129650
Leonid Kudryavtsev
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
kealon(Ruslan),
Я уже ссылку дал и под спойлер текст для 64 bit загнал. Адрес (третий параметр) у него должен быть в r8. Это так же и из ассемблерного кода видно.

kopiev,
Ну и молодец (на полном серьезе). Примерно так и оставить, мне только

aux_lo := aux_lo - aux_hi shl 32;

глаза режет. Т.к.:
1. Оно вообще не нужно. Приведение типа к (DWORD) само младшую часть и выделит.
2. AFAIK Обычно такие вещи общепринято делать через "двоичное И", наверное в Delph это and:

lo := value and 0xFFFFFFFF;

ну или как-то так

Какая нафиг оптимизация, когда у тебя одна операция умножения? Что Вы там оптимизируете? Во многих случаях, компилятор значительно более эффективный код сделает, т.к. авторы компиляторов обычно лучше знают правила и рекомендации Intel по написанию кода. Случайно вставив ассемблерную инструкцию которая даст "пенальти" или "промах" можно резко затормозить процессор на десятки тактов. Т.ч. все "улучшения" окажутся просто вредны.

Кроме того, если ф-цию сделать inline (наверняка Delphi это умеет), то компилятор сможет и окружающий код в точке ее вызова оптимизировать.

Если так уж хочется на ассемблере (что глупо и дико), то должно выглядить как-то так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function __Mul(a, b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD

// rcx = a
// rdx = b
// r8 = hiDword
mov rax, rcx
mul rdx                   // rax:rdx = a*b   Я надеюсь )))
mov rax, edx           // rax = loDword. В новых процах это zero latency инструкцию. 0 тактов.
shr rdx, 32              // rdx = hiDword
mov dword ptr [r8], edx    // Подозреваю тут мы можем словить пенальти. Нужно читать гайды


Как-то так. Понятное дело не проверял. Возможны ошибки. Скорее всего "dword ptr" вообще не нужен, т.к. размер задаст edx.
...
Рейтинг: 0 / 0
Умножение в ASM для x64-сборки
    #39129890
Barlone
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Leonid Kudryavtsev
Если так уж хочется на ассемблере (что глупо и дико), то должно выглядить как-то так:

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function __Mul(a, b: DWORD; var HiDWORD: DWORD): DWORD; // Result = LoDWORD

// rcx = a
// rdx = b
// r8 = hiDword
mov rax, rcx
mul rdx                   // rax:rdx = a*b   Я надеюсь )))
mov rax, edx           // rax = loDword. В новых процах это zero latency инструкцию. 0 тактов.
shr rdx, 32              // rdx = hiDword
mov dword ptr [r8], edx    // Подозреваю тут мы можем словить пенальти. Нужно читать гайды


Как-то так. Понятное дело не проверял. Возможны ошибки. Скорее всего "dword ptr" вообще не нужен, т.к. размер задаст edx.
Не правильно.Parameters less than 64 bits long are not zero extended; the high bits are not zeroed
ecx = a, edx = b, при этом старшие биты rcx,rdx не определены...
...
Рейтинг: 0 / 0
11 сообщений из 11, страница 1 из 1
Форумы / Программирование [игнор отключен] [закрыт для гостей] / Умножение в ASM для x64-сборки
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]