2016-06-12 2 views
2

У меня есть функция с 3 опорными аргументами, которая содержит некоторые ассемблерные коды. Я хочу получить результат этой функции в переменных R, G, B следующим образом.Передача опорных аргументов функции сборки

 void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B)  { 

    _asm { 
     push EAX; 
     xor EAX, EAX; 
     mov EAX,color; 
     mov R, AL; 
     mov G, AH; 
     shr EAX, 16; 
     mov B, AL; 
     pop EAX; 
    } 
    } 

, например я использовал функцию

DWORD color=RGB(76,0,0); 
uint8_t R, G, B; 
Get_RGB_color(color , R ,G ,B); 

Коды имеют две проблемы:

1- Получение неправильное значение в EAX, в строке мов EAX, цвет;

2- Ошибка 'размер операнда конфликт' в строках

мов R, AL; mov G, AH; mov B, AL;

Пожалуйста, помогите мне

+1

Ссылки фактически передаются как указатели, вам нужно рассматривать их как таковые. PS: для этого нет оснований использовать сборку. – Jester

+0

Я думаю, что получаю адрес переменных, Как я могу получить значение переменных? – SaeidMo7

+0

Я бы укрепил то, что сказал Шут. Считаете ли вы, что эта сборка будет быстрее, чем код, сгенерированный компилятором? –

ответ

7
push EAX; 

Почему вы толкая EAX здесь? Это не нужно делать. EAX является регистром регистрации вызывающего абонента, что означает, что вызывающий (, т. Е., ваша функция) свободен, чтобы скрыть его. Вы не обязаны сохранять свою ценность.
(EAX, EDX и ECX являются регистры абонентов сохранение в Win32 ABI, остальные вызываемая сохранение.)

Единственная другая причина, чтобы подтолкнуть реестр будет выровнять стек, но это тоже не обязательно. Стек будет выравниваться правильно, когда управление переходит к вашей функции.

xor EAX, EAX; 

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

mov EAX,color; 

Эта линия является неправильным; это то, что говорит ассемблерная ошибка. color передается этой функции как ссылка на DWORD, но под капотом ссылки реализуются как указатели, поэтому они фактически передаются как указатель на DWORD. Это означает, что вы не можете напрямую получить доступ к значению цвета - вы должны использовать указатель указателя (или "indirect addressing" на языке x86). Так как вы используете ассемблерные, вы можете позволить компилятору сделать стек бухгалтерию для вас и просто сослаться на ячейку памяти под именем формального параметра:

mov EAX, DWORD PTR [color] ; get the address of color 
mov EAX, DWORD PTR [EAX]  ; dereference it, storing the result in EAX 

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

mov R, AL; 

Здесь ассемблер дает вам ошибку "Операнд размер конфликта". Потому что R на самом деле является ссылкой, реализованной как указатель, это 32-бит. Это 32-разрядный указатель, указывающий на 8-разрядное местоположение в памяти. Таким образом, вы пытаетесь переместить 8-битное значение (AL) в 32-битное местоположение (указатель). Операнды имеют разные размеры. Итак, еще раз, вы должны использовать косвенную адресацию. Он выглядит так же, как код выше, за исключением того, что теперь R является байтами размера, и вы должны использовать другой регистр как регистр нуля, чтобы избежать затирания значения в EAX мы работали так трудно попасть:

mov EDX, DWORD PTR [R] ; get the address of R 
mov BYTE PTR [EDX], AL ; dereference it so we can store AL in there 

Это перемещает младший байт EAX (который мы можем назвать AL) в ячейку памяти размера байта, обозначенную R.

То же самое для следующей строки, за исключением того, что теперь вы перемещаете старший байт EAX (называемый AH). Мы можем повторно использовать EDX то здесь, потому что нам не нужно ее старое значение снова:

mov EDX, DWORD PTR [G] ; get the address of G 
mov BYTE PTR [EDX], AH ; dereference it so we can store AH in there 
shr EAX, 16; 

Это правильно.

mov B, AL; 

Третий стих, такой же, как первый. Как вы теперь знаете, это должно быть:

mov EDX, DWORD PTR [B] ; get the address of B 
mov BYTE PTR [EDX], AL ; dereference it so we can store AL in there 
pop EAX; 

Popping EAX теперь нет необходимости, так как мы не толкал EAX в самом начале.


Собираем все вместе, то вы получите следующую последовательность команд:

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{ 
    __asm 
    { 
     mov EAX, DWORD PTR [color] 
     mov EAX, DWORD PTR [EAX] 

     mov EDX, DWORD PTR [R] 
     mov BYTE PTR [EDX], AL 

     mov EDX, DWORD PTR [G] 
     mov BYTE PTR [EDX], AH 

     shr EAX, 16 
     mov EDX, DWORD PTR [B] 
     mov BYTE PTR [EDX], AL 
    } 
} 

Однако, это не самый оптимальный способ написания кода. Доступ к низким и высоким 8 битам 32-разрядного регистра, хотя и допустим, медленный. Оптимизирующий компилятор бы избежать этого, и в этом процессе, избежать необходимости в инструкции сдвига:

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{ 
    __asm 
    { 
     mov EAX, DWORD PTR [color] ; get the address of color 
     mov EAX, DWORD PTR [EAX]  ; get the value in EAX 

     mov EDX, DWORD PTR [R]  ; get the address of R 
     mov CL, BYTE PTR [EAX]  ; get the value of the lowest byte (8 bits) of color 
     mov BYTE PTR [EDX], CL  ; dereference R and store that byte in it 

     mov EDX, DWORD PTR [G]  ; get the address of G 
     mov CL, BYTE PTR [EAX + 1] ; get the value of the second-to-lowest byte in color 
     mov BYTE PTR [EDX], CL  ; dereference G and store that byte in it 

     mov EDX, DWORD PTR [B]  ; get the address of B 
     mov CL, BYTE PTR [EAX + 2] ; get the value of the third-to-lowest byte in color 
     mov BYTE PTR [EDX], CL  ; dereference B and store that byte in it 
    } 
} 

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

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{ 
    __asm 
    { 
      mov EAX, DWORD PTR [color] 
      mov EAX, DWORD PTR [EAX] 

      mov EDX, DWORD PTR [R] 
      movzx ECX, BYTE PTR [EAX] 
      mov BYTE PTR [EDX], CL 

      mov EDX, DWORD PTR [G] 
      movzx ECX, BYTE PTR [EAX + 1] 
      mov BYTE PTR [EDX], CL 

      mov EDX, DWORD PTR [B] 
      movzx ECX, BYTE PTR [EAX + 2] 
      mov BYTE PTR [EDX], CL 
    } 
} 

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

void Get_RGB_color(const DWORD &color, uint8_t &R, uint8_t & G, uint8_t & B) 
{ 
    R = (color & 0xFF); 
    G = ((color >> 8) & 0xFF); 
    B = ((color >> 16) & 0xFF); 
} 

Один финал примечание: вам не нужно заканчивать каждую инструкцию языка ассемблера точкой с запятой - даже при использовании синтаксиса встроенной сборки. Это необходимо только в C и C++. Причина, почему это не имеет значения, хотя, потому что точка с запятой на самом деле комментарий разделителем на ассемблере, так что было бы, как писать следующее C:

int foo;/**/ 
+0

Благодарим вас за помощь. – SaeidMo7

+2

@ SaeidMo7: Если этот ответ помог вам и решил вашу проблему, тогда вы должны подумать о принятии ответа. Более подробную информацию о хау и о том, как принять ответ, можно найти здесь: http://meta.stackexchange.com/a/5235/271768. Я также заметил, что вы никогда не принимали никаких ответов на ответы, которые сработали для вас. Вы, кажется, новы, и я предлагаю вернуться к другим вопросам и принять любые ответы, которые решили вашу проблему. Добро пожаловать в Stackoverflow! –

Смежные вопросы