2016-01-15 3 views
0

нужно немного понять, что делает этот встроенный asm (C++), чтобы я мог его правильно преобразовать, чтобы компилировать для x64. inline asm невозможно с Visual Studio и x64. мое исследование говорит мне, что я должен использовать intrinics ИЛИ помещать inline asm в asm-файл и помещать этот asm-файл в мой проект.inline asm to x64 - понимание

как вы можете я действительно не знаю, о чем я говорю, но вы должны получить общую идею.

Я действительно хотел бы понять, как получить этот встроенный asm для работы в компилированном коде x86 или x64. если бы я мог понять, что это делает, возможно, я смогу преобразовать в C++. или переместите этот встроенный asm в asm-файл. Я знаю, как перейти к отдельному файлу. проблема с переходом в asm-файл заключается в том, что я не уверен, как настроить мою функцию asm, чтобы принять параметр, который мне нужно передать. Я бы хотел, чтобы простой ответ, когда кто-то просто делает это для меня, НО то, что мне нужно, является объяснением, поэтому я могу в будущем сделать это самостоятельно. У меня есть два блока встроенного asm, и это, по-видимому, легче из двух.

inline asm to asm file

// FIRST inline asm talked about above 
// little endian 
void BlockInc(unsigned char *data) 
{ 
    #if DATA_BLOCK_SIZE==16 
    __asm 
    { 
     mov edi,[data] 
     add dword ptr [edi+0],1 
     adc dword ptr [edi+4],0 
     adc dword ptr [edi+8],0 
     adc dword ptr [edi+12],0 
    } 
    #else 
#error 
    #endif 
} 

//this is the second more difficult inline asm not mentioned 
void concThread(void *param) 
{ 
    unsigned long threadN = *((unsigned long *)param); 

    while(true) 
    { 
     unsigned long   index; 

     // 1. synch 
     WaitForSingleObject(concThread_semaphores1[threadN],INFINITE); 
     ReleaseSemaphore(concThread_semaphores2[threadN],1,NULL); 

     if(sharedStop) 
     { 
      _endthread(); 
     } 

     // start "sharedValue" concurrent modify 
     while(!sharedOkToGo); 

     for(index=0;index<(CYCLE_NUM/128);index++) 
     { 
      LARGE_INTEGER li; 

      QueryPerformanceCounter(&li); 

      if(threadN%2) 
      { 
       __asm 
       { 
        movzx ecx,byte ptr [li] 
        jecxz LOOP0_PREHEAD 
        jmp LOOP0_HEAD 

        LOOP0_PREHEAD: 
        inc ecx 
        LOOP0_HEAD: 
        dec sharedValue 
        loop LOOP0_HEAD 
       } 
      } 
      else 
      { 
       __asm 
       { 
        movzx ecx,byte ptr [li] 
        jecxz LOOP1_PREHEAD 
        jmp LOOP1_HEAD 

        LOOP1_PREHEAD: 
        inc ecx 
        LOOP1_HEAD: 
        inc sharedValue 
        loop LOOP1_HEAD 
       } 
      } 
     } 

     ReleaseSemaphore(concThread_semaphores2[threadN],1,NULL); 
    } 
} 

EDITED ASM: комментарий ниже предположил, что это не было правильно написано.

+0

Это одна из причин встроенного ассемблера не рекомендуется для x86, так и не поддерживаются для x64 или ARM. Этот код написан для оптимизации для некоторой древней платформы, когда он, вероятно, будет быстрее, чем C++. –

+0

Можете ли вы предложить способ выполнить эту же задачу, но с помощью C++? –

+0

Я сомневаюсь, что этот сборщик был когда-либо оптимальным для любой платформы, и это совсем не ясно, если вообще что-то полезно. Вам нужно выяснить, что это за предположение, и если он действительно должен быть полезен, полностью переписать его для использования атомных операций по мере необходимости. –

ответ

3

Для начала код неправильный. Учитывая, что inc не изменяет флаг переноса, следующее adc будет использовать начальное нулевое значение, чтобы оно никогда не перенесло ко второму слову.

Сообщалось, что если вы хотите преобразовать этот код самостоятельно, вам, конечно, потребуется ссылка на набор инструкций, чтобы узнать, что делает каждая инструкция. В этом случае, по-видимому, он хочет увеличить 128-битное число.

+0

Как этот код может быть изменен, чтобы на самом деле работать так, как вы предлагаете? Я смог отделить это от inline до asm-файла, но мой x64-переписывать не так хорошо. Я опубликую это позже! –

+0

Вместо 'inc dword ptr [edi + 0]' вы должны использовать 'add dword ptr [edi + 0], 1', и вы можете удалить' clc'. Автономная 64-битная версия - это всего лишь 3 команды: 'add qword ptr [rcx], 1; adc qword ptr [rcx + 8], 0; ret'. – Jester

+0

.Код BlockIncrement PROC, var1: QWORD \t мов RDI, var1 \t добавить QWORD PTR [RCX], 1 \t АЦП QWORD PTR [RCX + 8], 0 \t RET BlockIncrement ENDP КОНЕЦ –

1

Это

movzx ecx,byte ptr [li] 
jecxz LOOP0_PREHEAD 
jmp LOOP0_HEAD 

LOOP0_PREHEAD: 
inc ecx 
LOOP0_HEAD: 
dec sharedValue 
loop LOOP0_HEAD 

выглядит

// ecx was used to hold a loop count 
uint32_t i = li; 
// do-while to guarantee execution at least once 
// since LOOP0_PREHEAD incremented ecx if it was zero 
do { 
    sharedValue--; 
    i--; 
} while (i > 0); 
+1

Так код выглядит так, как будто он выполняет некоторую проверку/проверку по нескольким потокам, обращаясь к одной и той же ячейке памяти ('sharedValue'). Я считаю, что цель asm в оригинале - гарантировать, что обращения к памяти не будут переупорядочены, отложены или оптимизирован. В MSVC++ доступ к 'sharedValue' через ссылку' volatile' может дать аналогичные результаты. Также возможно, что они хотели убедиться, что 'sharedValue' обновлен с использованием' dec' и 'inc', которые обеспечивают некоторую атомарность. Использование операторов C может не отображаться на 'inc' /' dec' на уровне машины. –

+1

@MichaelBurr Если 'std :: atomic' доступен,' std :: atomic sharedValue; 'а затем' sharedValue.fetch_sub (1); 'может быть предпочтительнее? –

+0

Определенно - я должен был подумать об этом. –