Компилятор: gcc 4.7.1, 32bit, ubuntu
Вот пример:
int main(void)
{
unsigned int mem = 0;
__asm volatile
(
"mov ebx, esp\n\t"
"mov %0, [ds : ebx]\n\t"
: "=m"(mem)
);
printf("mem = 0x%08x\n", mem);
return 0;
}
gcc -masm=intel -o app main.c
Сообщения ассемблера: invalid use of register!
Как я знаю, ds и ss указывают на один и тот же сегмент. Я не знаю, почему я не могу использовать логический адрес [ds: ebx] для адресации.
У вашего кода две проблемы:
Один: ссылка косвенной памяти должна быть:
mov %0, ds : [ebx]
То есть, с ds
из скобок.
Два: вы используете ограничение памяти (=m
) для обращения к переменной mem
. Это невозможно, потому что это локальная переменная и, как таковая, не имеет фиксированного адреса. Более того, одна команда не может иметь как начало, так и пункт назначения в памяти, вы должны использовать регистр. Самый простой способ - указать =g
что в основном означает что угодно, но в вашем случае это невозможно, потому что esp
нельзя перенести непосредственно в память. Вы должны использовать =r
.
Три: (?) Вы клонируете ebx
, поэтому вы должны объявить его как таковой или иначе не использовать его таким образом. Это не помешает компиляции, но заставит ваш код вести себя беспорядочно.
Вкратце:
unsigned int mem = 0;
__asm volatile
(
"mov ebx, esp\n\t"
"mov %0, ds : [ebx]\n\t"
: "=r"(mem) :: "ebx"
);
Или лучше не ebx
использовать ebx
, пусть вместо этого компилятор решит:
unsigned int mem = 0, temp;
__asm volatile
(
"mov %1, esp\n\t"
"mov %0, ds : [%1]\n\t"
: "=r"(mem) : "r"(temp)
);
Кстати, вам не нужно ключевое слово volatile
в этом коде. Это используется для предотвращения оптимизации ассемблера, даже если выход не нужен. Если вы напишете код для побочного эффекта, добавьте volatile
, но если вы напишете код для получения результата, не добавляйте volatile
. Таким образом, если оптимизирующий компилятор определяет, что выход не нужен, он удалит весь блок.
volatile
также запрещает компилятору перемещать или переупорядочивать код сборки относительно другого кода (например, выводить его из цикла).