Конференция "Начинающим" » несколько вопросов по асемблеру
 
  • cryptologic © (11.02.17 20:48) [0]
    1 можно ли
    push ebx

    выносить за пределы текущей функции/процедуры

    например здесь

    function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
    var _Result: Longword;

    procedure push_registr;
    begin
     case Register_Name of
       EDX:
         asm
         {$IFDEF CPUx86}
         push ebx
        {$ELSE CPUx64}
         mov r10, rbx
        {$ENDIF}
       end;
       ECX:
         asm
         {$IFDEF CPUx86}
         push ecx
         {$ELSE CPUx64}
         mov r10, rcx
        {$ENDIF}
       end;
       ECX:
         asm
         {$IFDEF CPUx86}
         push ecx
         {$ELSE CPUx64}
         mov r10, rcx
         {$ENDIF}
       end;
     end;
    end;

    procedure pop_register;
    begin
     case Register_Name of
       EDX:
         asm
           {$IFDEF CPUX86}
           pop edx
           {$ENDIF}
           {$IFDEF CPUX64}
           mov rdx, r10
           {$ENDIF}
         end;
       ECX:
         asm
          {$IFDEF CPUX86}
           pop ecx
          {$ENDIF}
          {$IFDEF CPUX64}
          mov rcx, r10
          {$ENDIF}
         end;
       EBX:
         asm
          {$IFDEF CPUX86}
          pop ebx
          {$ENDIF}
          {$IFDEF CPUX64}
          mov rbx, r10
          {$ENDIF}
         end;
     end;
    end;

    begin
     Case Register_Name of
       EDX:
         asm
          call push_registr;
           mov eax, EAX_Leaf
           cpuid
           mov _Result, edx
          call pop_registr
         end;
       ECX:
         asm
        call push_registr;
           mov eax, EAX_Leaf
           cpuid
           mov _Result, ecx
     call pop_registr
         end;
       EBX:
         asm
       call push_registr;
          mov eax, EAX_Leaf
          cpuid
          mov _Result, ebx
       call pop_registr
         end;
     End;
     if (_Result and (1 shl bit)) = (1 shl bit) then Result := true
     else Result := false;
    end;

  • cryptologic © (11.02.17 20:55) [1]
    2. вопрос "push"  она в делфи обязательна, я где то читал, что компилятор сам автоматически делает сохранение регистров перед вызовом директив "ASM ... END" . И кажется в одной из статей Анатолия Подгорецкого, но вот проблема уже не могу найти его статью, а может и не у него читал
  • Игорь Шевченко © (11.02.17 20:58) [2]
    Не надо желать странного. Гораздо проще запоминать значения всех регистров перед вызовом cpuid, сохранять полученные значения в памяти и восстанавливать регистры
  • cryptologic © (11.02.17 21:14) [3]
    Стало быть все-таки вот так

    function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
    var _Result: Longword;
    begin

     Case Register_Name of
       EDX:
         asm
          {$IFDEF CPUX86} push edx {$ENDIF}
          {$IFDEF CPUX64} mov r10, rdx {$ENDIF}
           mov eax, EAX_Leaf // https://en.wikipedia.org/wiki/CPUID
           cpuid
           // db $0F,$A2 = CPUID instruction
           mov _Result, edx
          {$IFDEF CPUX86} pop edx {$ENDIF}
          {$IFDEF CPUX64} mov rdx, r10 {$ENDIF}
         end;

       ECX:
         asm
           {$IFDEF CPUX86} push ecx {$ENDIF}
           {$IFDEF CPUX64} mov r10, rcx {$ENDIF}
           mov eax, EAX_Leaf
           cpuid
           //db $0F, $A2
           mov _Result, ecx
          {$IFDEF CPUX86} pop ecx {$ENDIF}
          {$IFDEF CPUX64} mov rcx, r10 {$ENDIF}
         end;

       EBX:
         asm
           {$IFDEF CPUX86} push ebx {$ENDIF}
           {$IFDEF CPUX64} mov r10, rbx {$ENDIF}
            mov eax, EAX_Leaf
            cpuid
            mov _Result, ebx
          {$IFDEF CPUX86} pop ebx {$ENDIF}
          {$IFDEF CPUX64} mov rbx, r10 {$ENDIF}
         end;
     End;

     if (_Result and (1 shl bit)) = (1 shl bit) then Result := true
     else Result := false;

    end;

  • cryptologic © (11.02.17 21:17) [4]
    О...!!! теперь у меня универсальная функция есть, для проверки процессоров
  • cryptologic © (11.02.17 21:25) [5]
    Все-таки "ASM" нужен все сильнее и сильнее, все чаще стал встречаться там где он рулит.   Вот его  и первое применение  мной https://forum.bits.media/uploads/monthly_02_2017/post-44867-0-52595600-1486515752_thumb.png
  • cryptologic © (11.02.17 21:26) [6]
  • cryptologic © (11.02.17 23:01) [7]
    Готовый мод

    unit cpu_info_xe;

    interface
    USES Winapi.Windows, System.SysUtils, System.Win.Registry;

    Type
     TCPUInstruction = (cpu_MMX, cpu_SSE, cpu_SSE2, cpu_SSE3, cpu_SSSE3, cpu_SSE_4_1, cpu_SSE_4_2, cpu_AVX, cpu_AVX2, cpu_AES);

    Type TRegisterName = (EBX, ECX, EDX);

    const
     strCPUFeature : array [TCPUInstruction] of string =
      ('MMX', 'SSE', 'SSE2', 'SSE3', 'SSSE3', 'SSE4.1', 'SSE4.2', 'AVX', 'AVX2', 'AES');

    function DetectCPUFeature(CPUInstruction: TCPUInstruction): Boolean;
    function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;

    implementation

    function CPUFeature(EAX_Leaf: integer; Register_Name: TRegisterName; Bit: ShortInt): boolean;
    var _Result: Longword;
    begin

     Case Register_Name of
       EDX:
         asm
          {$IFDEF CPUX86} push edx {$ENDIF}
          {$IFDEF CPUX64} mov r10, rdx {$ENDIF}
           mov eax, EAX_Leaf // https://en.wikipedia.org/wiki/CPUID
           cpuid
           // db $0F,$A2 = CPUID instruction
           mov _Result, edx
          {$IFDEF CPUX86} pop edx {$ENDIF}
          {$IFDEF CPUX64} mov rdx, r10 {$ENDIF}
         end;

       ECX:
         asm
           {$IFDEF CPUX86} push ecx {$ENDIF}
           {$IFDEF CPUX64} mov r10, rcx {$ENDIF}
           mov eax, EAX_Leaf
           cpuid
           //db $0F, $A2
           mov _Result, ecx
          {$IFDEF CPUX86} pop ecx {$ENDIF}
          {$IFDEF CPUX64} mov rcx, r10 {$ENDIF}
         end;

       EBX:
         asm
           {$IFDEF CPUX86} push ebx {$ENDIF}
           {$IFDEF CPUX64} mov r10, rbx {$ENDIF}
            mov eax, EAX_Leaf
            cpuid
            mov _Result, ebx
          {$IFDEF CPUX86} pop ebx {$ENDIF}
          {$IFDEF CPUX64} mov rbx, r10 {$ENDIF}
         end;
     End;

     if (_Result and (1 shl bit)) = (1 shl bit) then Result := true
     else Result := false;

    end;

    function DetectCPUFeature(CPUInstruction: TCPUInstruction): Boolean;
    var
     _Result: Longword;
    begin
     // https://en.wikipedia.org/wiki/CPUID
     Case CPUInstruction of
       cpu_MMX:     Result := CPUFeature(1, EDX, 23); // MMX instructions EAX=1 EDX=23
       cpu_SSE:     Result := CPUFeature(1, EDX, 25); // SSE instructions EAX=1 EDX=25
       cpu_SSE2:    Result := CPUFeature(1, EDX, 26); // SSE2 instructions EAX=1 EDX=26
       cpu_SSE3:    Result := CPUFeature(1, ECX, 0);  // SSE3 instructions ECX=1 ECX=0
       cpu_SSSE3:   Result := CPUFeature(1, ECX, 9);  // SSE instructions EAX=1 ECX=9
       cpu_SSE_4_1: Result := CPUFeature(1, ECX, 19); // SSE instructions EAX=1 ECX=19
       cpu_SSE_4_2: Result := CPUFeature(1, ECX, 20); // SSE instructions EAX=1 ECX=20
       cpu_AVX:     Result := CPUFeature(1, ECX, 28); // SSE instructions EAX=1 EDX=28
       cpu_AVX2:    Result := CPUFeature(7, EDX, 5); // SSE instructions EAX=7 EDX=5
       cpu_AES:     Result := CPUFeature(1, ECX, 25); // SSE instructions EAX=1 ECX=25
     End;
    end;

    end.



    Можно применять разовым вызовом или в цикле

     if DetectCPUFeature(cpu_AVX) then ShowMessage(strCPUFeature[TCPUInstruction(cpu_AVX)] + ' инструкции поддерживаются')
     else ShowMessage(strCPUFeature[TCPUInstruction(cpu_AVX)] + ' инструкции не поддерживаются');

     for i := 0 to Ord(High(TCPUInstruction)) do
       if DetectCPUFeature(TCPUInstruction(i)) then mm.Lines.Add(strCPUFeature[TCPUInstruction(i)] + ' инструкции поддерживаются')
       else mm.Lines.Add(strCPUFeature[TCPUInstruction(i)] + ' инструкции не поддерживаются');  

  • cryptologic © (11.02.17 23:06) [8]
    Если кому нужно протестируйте потом напишите что и как, у меня нет такого количества разных процессоров, что бы на всех опробовать
  • cryptologic © (12.02.17 05:19) [9]
    В модуле исправить нужно

    // ..................
      EBX:
        asm
          {$IFDEF CPUX86} push ebx {$ENDIF}
          {$IFDEF CPUX64} mov r10, rbx {$ENDIF}
           mov eax, EAX_Leaf
           mov ecx, 0           <- дописать комманду
           cpuid
           mov _Result, ebx
         {$IFDEF CPUX86} pop ebx {$ENDIF}
         {$IFDEF CPUX64} mov rbx, r10 {$ENDIF}
        end;
    // ..................

    изменить строчку    
    cpu_AVX2:    Result := CPUFeature(7, EDX, 5); // SSE instructions EAX=7 EDX=5
    на новую
    cpu_AVX2:    Result := CPUFeature(7, EBX, 5); // SSE instructions EAX=7 EBX=5
  • Rouse_ © (12.02.17 10:45) [10]
    На 64 битах не заработает
  • megavoid © (12.02.17 15:57) [11]
  • cryptologic © (14.02.17 12:26) [12]

    > Rouse_ ©   (12.02.17 10:45) [10]
    >
    > На 64 битах не заработает


    Имеется ввиду:
    1. на 64 битных процессорах ?
    2. не откомпилируется в 64 битный код

    если не откомпилируется 64 битный код, то это пока мне и не нужно
    тогда это можно убрать {$IFDEF CPUX64} ...... {$ENDIF} или это все-таки нужно?


    > megavoid ©   (12.02.17 15:57) [11]

    большое спасибо код очень полезен для изучения
  • Rouse_ © (14.02.17 14:46) [13]

    > cryptologic ©   (14.02.17 12:26) [12]
    > 2. не откомпилируется в 64 битный код

    инлайны в 64 битах - нонсенс
  • cryptologic © (16.02.17 18:06) [14]

    > Rouse_ ©   (14.02.17 14:46) [13]
    >
    >
    > > cryptologic ©   (14.02.17 12:26) [12]
    > > 2. не откомпилируется в 64 битный код
    >
    > инлайны в 64 битах - нонсенс


    Инлайны это вот это "asm end"?
    как же быть? как вставить в 64 битной версии ассемблерную вставку?

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

    Еще интересует вопрос:

    Еще одну функию сделал

    function GetCPUVendor: AnsiString;
    var _bx, _dx, _cx: LongWord;
    begin
     SetLength(Result, 12);
     FillChar(result, length(Result), #0);
     asm
     {$IFDEF CPUX86}
       PUSHAD
       xor eax, eax
       CPUID
       mov _bx, ebx
       mov _dx, edx
       mov _cx, ecx
       POPAD
     {$ENDIF}
     {$IFDEF CPUX64}
       push rad
       push rbx
       push rdx
       push rcx
       xor rax, rax
       CPUID
       mov _bx, rax
       mov _dx, rdx
       mov _cx, rcx
       pop rcx
       pop rdx
       pop rbx
       pop rad
     {$ENDIF}
     end;
      move(_bx, Result[1], 4);
      move(_dx, Result[5], 4);
      move(_cx, Result[9], 4);
    end;


    А как то можно  move(_bx, Result[1], 4); это сделать на ассемблере так, что бы сразу в Result записывать
    Пробовал вот так

    mov eax, @Result[1]
    mov [eax], edx
    mov [eax + 4], ebx
    mov [eax + 8], ecx


    делал и так

    mov @Result[1], ebx
    mov @Result[5], edx
    ......


    Возникает ошибка записи в память
  • cryptologic © (16.02.17 18:17) [15]
    Еще одну функцию сделал для проверки доступности CPUID

    function IsCPUIDSuported: boolean;
    var di_before, di_after : LongWord;
    begin

     asm
       push edi;
       mov di_before, edi
       btc edi, 21 //200000h
       mov di_after, edi
       pop edi
     end;

     if di_before <> di_after then Result := true
     else Result := false;

    end;



     if di_before <> di_after then Result := true
     else Result := false;



    И вот без этого обойтись не смог. Можно ли как то на ASM установить результат функции?
  • Игорь Шевченко © (16.02.17 18:37) [16]

    >  if di_before <> di_after then Result := true
    >  else Result := false;



    > Можно ли как то на ASM установить результат функции?


    Вместо


    >   mov di_after, edi
    >    pop edi


    cmp edi,di_before
    pop edi
    setne al

  • cryptologic © (21.02.17 14:35) [17]

    > Игорь Шевченко ©   (16.02.17 18:37) [16]


    проанализировал свой код и ваше предложение и пришел к выводу ваше предложение не подходит
    и сделал такой код  т.к. команда btc инвертирует бит с 0 на 1 с 1 на 0
    и состояние измененного бита по результату может быть любым и не только 1 но и 0,   стало быть анализировать командой cmp edi,di_before не всегда будет правильно

    анализировать изменение бита через XOR надежнее
    мой вариант:

     asm
        push edi;
        push eax
        mov eax, edi
        btc edi, 21 //200000h
        xor eax, edi
        shr eax, 21
        mov Result, al
        pop eax
        pop edi
     end;

  • cryptologic © (21.02.17 14:44) [18]
    Интересно как будут работать инструкции asm 386+ на разных такм на Win10 + rasbpery pi 2/3 и других платформах?
  • Игорь Шевченко © (21.02.17 15:07) [19]

    > Интересно как будут работать инструкции asm 386+ на разных
    > такм на Win10 + rasbpery pi 2/3 и других платформах?


    Никак
  • Германн © (22.02.17 03:13) [20]
    Удалено модератором
 
Конференция "Начинающим" » несколько вопросов по асемблеру
Есть новые Нет новых   [118585   +35][b:0][p:0.005]