Конференция "Прочее" » Передача параметров функции
 
  • Rouse_ © (01.06.16 16:59) [40]

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

    Ну так это же настройки компилятора, а не отладчика :)
  • Pavia © (01.06.16 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_ © (01.06.16 17:08) [42]

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

    ничего не понял, ты хочешь сказать что для других инструкций префикс 0x67 не используется, только для LOOP? :)
  • Pavia © (01.06.16 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_ © (01.06.16 17:30) [44]

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

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

    66E2E5         loop $005b1fe4

    здесь прыжок произойдет не на адрес 005b1fe4 а на адрес 00001fe4
  • SergP © (02.06.16 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_ © (02.06.16 13:19) [46]
    ну вот такой компилятор :)
  • DayGaykin © (02.06.16 13:26) [47]
    А можно вкратце, раз уж тема зашла, какие еще регистры нужно сохранять? И в 64 битах.
  • Rouse_ © (02.06.16 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 © (02.06.16 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 © (02.06.16 16:28) [50]
    Мда. уже нашел где я протупил
  • dmk © (02.06.16 20:10) [51]
    jmp @@continue

    @@continue:
  • SergP © (02.06.16 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 © (02.06.16 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 © (03.06.16 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 © (03.06.16 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_ © (03.06.16 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 © (03.06.16 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 © (03.06.16 13:44) [58]
    Rouse_ ©   (03.06.16 13:06) [56]

    Спасибо! Будем знать ;)
  • SergP © (03.06.16 13:49) [59]
    Кстати, в какой версии Delphi встроенный ассемблер поддерживает мнемоники SSE4.2?
 
Конференция "Прочее" » Передача параметров функции
Есть новые Нет новых   [134432   +19][b:0][p:0.002]