Некоторые вопросы по встроенному ассемблеру

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

Есть блок кода, который я пробовал в VC++ 2010 Express (я пытаюсь получить информацию из инструкции CPUID): `

int main()
{
char a[17]; //containing array for the CPUID string
a[16] = '\0'; //null termination for the std::cout
void *b=&a[0]; 
int c=0; //predefined value which need to be loaded into eax before cpuid

_asm
{
    mov eax,c;
    cpuid;
    mov [b],eax;
    mov [b+4],ebx;
    mov [b+8],ecx;
    mov [b+12],edx;
}
std::cout<<a;
}`

Итак, чтобы подвести итог, я попытался создать пустой указатель на первый элемент массива, а затем, используя косвенную адресацию, просто переместить значения из регистров. Но этот подход дает мне «стек вокруг переменной b поврежден во время выполнения», но я не знаю, почему.

Пожалуйста помоги. Спасибо. И это только в учебных целях, я знаю, что есть функции для CPUID....

РЕДАКТИРОВАТЬ: Кроме того, как вы можете использовать прямую адресацию в встроенном ассемблере x86 VC++ 2010? Я имею в виду, что общий синтаксис для непосредственной загрузки номера в 8051 - это mov src,#number, но в VC++ asm это mov dest,number без знака #. Итак, как сообщить компилятору, что вы хотите получить прямой доступ к ячейке памяти с адресом x?


person B.Gen.Jack.O.Neill    schedule 06.11.2010    source источник
comment
Вам вообще не нужен c. Просто используйте 'xor eax,eax', чтобы установить eax=0.   -  person TonyK    schedule 29.11.2010


Ответы (2)


Причина, по которой ваш стек поврежден, заключается в том, что вы сохраняете значение eax в b. Затем сохранить значение ebx в ячейке памяти b+4 и т. д. Синтаксис встроенного ассемблера [b+4] эквивалентен выражению C++ &(b+4), если бы b был указателем на байт.

Вы можете увидеть это, если посмотрите b и одиночный шаг. Как только вы выполните mov [b],eax, значение b изменится.

Один из способов решить эту проблему — загрузить значение b в индексный регистр и использовать индексированную адресацию:

mov edi,[b]
mov [edi],eax
mov [edi+4],ebx
mov [edi+8],ecx
mov [edi+12],edx

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

lea edi,a
mov [edi],eax
... etc ...

Если вы возитесь со встроенным ассемблером, неплохо было бы открыть окно «Регистры» в отладчике и посмотреть, как все изменится при пошаговом выполнении.

Вы также можете напрямую обращаться к памяти:

mov dword ptr a,eax
mov dword ptr a+4,ebx
... etc ...

Однако подобная прямая адресация требует больше байтов кода, чем индексированная адресация в предыдущем примере.

Я думаю, что вышеизложенное с инструкцией lea (загрузить эффективный адрес) и прямой адресацией, которую я показал, отвечает на ваш последний вопрос.

person Jim Mischel    schedule 06.11.2010

Совет открыть окно «Регистры» в отладчике и посмотреть, как все изменится, не будет работать в VC++ 2010 Express.

Вы можете быть так же удивлены, как и я, обнаружив, что в VC++ 2010 Express ОТСУТСТВУЕТ окно регистров. Это особенно удивительно, поскольку пошаговая разборка работает.

Единственный известный мне обходной путь — открыть окно просмотра и ввести имена регистров в поле «Имя». Введите EAX EBX ECX EDX ESI EDI EIP ESP EBP EFL и CS DS ES SS FS GS, если хотите.

ST1 ST2 ST3 ST4 ST5 ST6 ST7 также работают в окне просмотра.

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

person David Galloway    schedule 20.07.2011