Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 53, средняя оценка - 4.85
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
#1

Ошибка компиляции ассемблерной вставки - C++

08.11.2009, 16:39. Просмотров 7127. Ответов 21
Метки нет (Все метки)

Добрый вечер. Захотелось мне сделать ассемблерную вставку в C++ код. Сделал. Но компилятору MinGW чето не нравится. Выдает следующие ошибки в 8 строке:

error: expected `(' before '{' token
error: expected asm body before '{' token

http://www.cyberforum.ru/cpp/thread1395376.html

Что я сделал не так ?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
 
using namespace std;
int main ()
{
    cout << "Сейчас будет звонить!" << endl;
    asm
    {
        /*MOV AH,2
        MOV DL,7
        INT 21H*/
    }
    cout << "Есть!" << endl;
    return 0;
}
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.11.2009, 16:39
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Ошибка компиляции ассемблерной вставки (C++):

Ошибка сегментирования при компиляции
Когда компилирую через g++ компилируется, при запуске выдает ошибку...

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

Метки в макросах в ассемблерной вставке
В C++ написан макрос с ассемблерной вставкой, который содержит в себе метку...

Ошибка компиляции
при компиляции выскакивает ошибка: undefined symbol 'memo1'....в последней...

Ошибка компиляции
есть во такой код в Project -&gt; View Source try { if(TForm6::Execute()){...

21
HIMen
4249 / 1416 / 101
Регистрация: 12.04.2009
Сообщений: 2,346
08.11.2009, 17:50 #2
__asm
0
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
08.11.2009, 17:54  [ТС] #3
Цитата Сообщение от HIMen Посмотреть сообщение
__asm
Те же ошибки
0
Goodwin98
2521 / 817 / 10
Регистрация: 31.05.2009
Сообщений: 1,672
10.11.2009, 19:03 #4
Почитайте тут.

Добавлено через 2 минуты
Цитата Сообщение от RNT Посмотреть сообщение
Но компилятору MinGW чето не нравится. Выдает следующие ошибки в 8 строке:
У него вроде AT&T синтаксис, а не интеловский и команды будут выглядеть по другому.

Примерно так
C++
1
2
3
4
5
    asm ( 
"movb $2,%ah \n" 
"movb $7,%dl\n" 
"int $0x21\n"
);
1
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
10.11.2009, 19:45  [ТС] #5
Цитата Сообщение от Goodwin98 Посмотреть сообщение
asm (
"movb $2,%ah \n"
"movb $7,%dl\n"
"int $0x21\n"
);
Компилится. Но возникли следующие вопросы:

1) Как сделать нормальный Intel синтаксис ?
2) Почему команды в круглых скобках а не в фигурных ?
3) Почему каждая команда в кавычках ?
4) Почему в конце каждой команды стоит знак переноса строки ?
5) Почему при построчной отладке программы все ассемблерные команды пропускаются ?
6) Почему после "выполнения" команд в регистрах не оказывается нужного значения ?
0
Gravity
569 / 563 / 64
Регистрация: 29.01.2009
Сообщений: 1,274
10.11.2009, 20:47 #6
RNT, у каждого компилятора свой синтаксис асм-вставок. MinGW это портированный в винду GCC со своими особенностями. Если понимаешь по англицки, то вот тебе туториал на эту тему http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html.
1
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
10.11.2009, 23:54 #7
Если что - обращайся. Правда я в intel'овском ассемблере ничерта не понимаю, но если объяснишь, что да как должно быть - попробую написать или объяснить. Почитай ещё эту тему. В конечном итоге в посте 49 я наваял конкретную реализацию для поставленного вопроса, но попробуй всю тему прочитать, может среди этого бардака какое-то общее понимание появится
1
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
11.11.2009, 00:22  [ТС] #8
Я не понимаю, почему в компилятор GCC засунули ассемблер GAS с чудо-юдо синтаксисом AT&T ? Для него даже книжек почти нет.
0
Gravity
569 / 563 / 64
Регистрация: 29.01.2009
Сообщений: 1,274
11.11.2009, 00:46 #9
У AT&T нормальный синтаксис и в чем-то даже удобнее интеловского. AT&T асм появился в UNIX, когда интела еще в помине не было и так и остался классическим асмом для юникс-систем. Книги для него, кстати, есть, но все в английском варианте, а на русском можешь почитать статью http://wasm.ru/article.php?article=asm_linux_for_c
1
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
11.11.2009, 00:56  [ТС] #10
Цитата Сообщение от Gravity Посмотреть сообщение
Книги для него, кстати, есть, но все в английском варианте


Добавлено через 2 минуты
Значит буду изучать intel`овский синтаксис, я еще не настолько хорошо знаю инглиш
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
11.11.2009, 09:47 #11
В gcc НЕ "интеловский" или какой-либо другой синтаксис (а точнее, "ФОРМАТ АССЕМЛЕРНОЙ ВСТАВКИ"). Этот синтаксис - единый для ВСЕХ архитектур. Отличие идёт только в constraint'ах (ну и, понятное дело, в самом ассемблерном тексте). Мне уже приходилось писать документацию по формату gnu вставки, сегодня постараюсь на работе найти. Если вдруг случится, что ты это просечёшь досконально, то тогда поймёшь, что более идеально придумать сложно.
0
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
11.11.2009, 10:37  [ТС] #12
Не понимаю, объясни пожалуйста попроще.

Цитата Сообщение от Evg Посмотреть сообщение
Этот синтаксис - единый для ВСЕХ архитектур
AT&T ? Он более кроссплатформенный чем Intel-синтаксис ?

Цитата Сообщение от Evg Посмотреть сообщение
Отличие идёт только в constraint'ах
Что это такое ? constraint ?

Я вот нарыл на одном форуме, как сделать чтобы g++ компилил intel-синтаксис.
Надо в консоли делать так: g++ имя_сорца.cpp -masm=intel
http://www.google.ru/search?hl=ru&ne...ng_ru&aq=f&oq=
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
11.11.2009, 13:48 #13
Сразу на всякий случай скажу: есть два понятия:
- "синтаксис ассемблера" - зависит от архитектуры
- "формат ассемблерной вставки" (ассемблерная вставка это конструкция ЯЗЫКА GNU-C) - от архитектуры не зависит

По поводу документации. Я её нашёл, но хз насколько она окажется полезной. Дело было так, что партия сказала "надо", комсомол сказал "есть" и сделал абы как, лишь бы отстали. Т.е. документация скорее "чтоб было", чем "чтоб можно было пользоваться". Реально она больше введёт в заблуждение, т.к. описано на примере sparc. В общем я дла начала закину, а ты хоть базу почитай

=================================

GNU ассемблерная вставка по замыслу разработчиков является чёрным ящиком с параметрами, т.е. компилятор НЕ видит ассемблерного текста вставки, но видит описание всех ресурсов, которые подаются на вход вставки (input arguments), принимаются с выхода вставки (output arguments) и неявным образом портятся внутри вставки (clobbers)

Формат вставки такой:

C
1
asm ("<asm text>" : <input arguments> : <output arguments> : <clobbers>);
Рассмотрим сначала просто пример, как построить выражение 'x = y + z' при помощи
gnu ассемблерной вставки:

C
1
2
3
4
5
{
  int x, y, z;
  ...
  asm ("add %1, %2, %0" : "=r"(x) : "r"(y), "r"(z));
}
в данном случае:
* "add %1, %2, %0" - текст вставки,
* "=r"(x) - ВЫХодной аргумент (одна штука),
* "r"(y), "r"(z) - ВХодные аргументы (две штуки, перечисленные через запятую).
* clobber'ы в данной вставке отсутствуют, а потому не написаны

Описание аргументов вставки состоит из двух частей - в кавычках пишется модификатор (FIXME КАК ПРАВИЛЬНО НАЗЫВАЕТСЯ???) (только для output аргументов) и описание аппаратного ресурса, на который должен быть загружен аргумент вставки (это называют словом constraint). В круглых скобках пишется значение (value) аргумента: для input аргумента это rvalue expression (выражение, которое может стоять в правой части присваивания), для output аргумента - это lvalue expression (соответственно, выражение, которое может стоять в левой части присваивания)

Более детально будет расписано ниже, а пока только применительно к данному примеру. У output аргумента "=r"(x) в качестве модификатора стоИт символ '=', что означает аргумент строго на запись. В качестве constraint стоИт символ 'r', что означает целочисленный регистр, доступный компилятору для распределения. В качестве value стоИт x, это означает, что после кода вставки значение упомянутого регистра будет записано в переменную x. У input аргумента "r"(y) в качестве constraint так же стоит целочисленный регистр, в качестве value стоИт y, что означает, что перед кодом вставки значение переменной y будет загружено на регистр, который затем будет использоваться во вставке.

Текст вставки - это то, что в итоге попадает в выходной ассемблерный код, который строит компилятор. Символ % является управляющим. %0, %1 и %2 соответсвуют номерам аргументов в порядке их перечисления в конструкции asm начиная с нуля. В данном случае %0 соответствует аргументу "=r"(x), %1 соответствует аргументу "r"(y), а %2 соответствует аргументу "r"(z).

Добавлено через 56 секунд
Ну и в добавок, ты всегда можешь запустить gcc/g++ с опцией -S и посмотреть результирующий ассемблерный файл (чтобы визуально оценить, насколько правильный код построился)
1
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
11.11.2009, 15:04  [ТС] #14
Цитата Сообщение от Evg Посмотреть сообщение
asm ("add %1, %2, %0" : "=r"(x) : "r"(y), "r"(z));
Ты кажется перепутал порядок управляющих символов. Я правильно поправил ?

C++
1
asm ("add %0, %1, %2" : "=r"(x) : "r"(y), "r"(z));
Я попробовал скомпилировать твой код, выдается ошибка Error: suffix or operands invalid for `add' в строке 119. Такой строки в моем коротеньком исходнике нет.

C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
 
int main()
{
    int x=0, y=6, z=7;
    asm ("add %1, %2, %0" : "=r"(x) : "r"(y), "r"(z));
    cout << x;
    return 0;
}
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
11.11.2009, 15:16 #15
> Ты кажется перепутал порядок управляющих символов. Я правильно поправил ?

У меня всё правильно. Для sparc'овской операции формат такой "add src1, src2, dst"

Добавлено через 1 минуту
> Я попробовал скомпилировать твой код

Это для sparc'а, а не для intel'а. Скажи мне, как на intel'е делается сложение, и я тебе исходник напишу. Эту ошибку выдаёт ассемблер, а не компилятор. gcc вовнутрь вставки вообще не лезет, только подставляет операнды на нужные позиции
0
Gravity
569 / 563 / 64
Регистрация: 29.01.2009
Сообщений: 1,274
11.11.2009, 15:21 #16
Для интела будет так выглядеть
C++
1
asm ("add %0, %1" : "=m"(x) : "r"(y));
add принимает два операнда. Компилировать надо с флагом intel, иначе не фкурит.

Мне кажется, что проще писать процедуру на асме отдельным файлом и собирать вместе с основным проектом на си, если так хочется поюзать ассемблер.
1
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
11.11.2009, 15:30 #17
Gravity, у тебя задан двухоперандный случай. К тому же правильно помечать "+m", а не "=m". Вариант с оформлением в виде отдельной процедуры (для трёхаргументного вычитания):

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
int
asm_sub (int src1, int src2)
{
  register int dst;
 
  asm ("subl %2, %0" : "=&r" (dst) : "0" (src1), "r" (src2));
 
  return dst;
}
 
int main (void)
{
  printf ("%d\n", asm_sub (15, 23));
  return 0;
}
Добавлено через 25 секунд
Цитата Сообщение от Gravity Посмотреть сообщение
Мне кажется, что проще писать процедуру на асме отдельным файлом и собирать вместе с основным проектом на си, если так хочется поюзать ассемблер.
В этом случае ты зарубаешь возможность inline'а
2
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
11.11.2009, 15:59  [ТС] #18
Подскажите пожалуйста книжки или статьи, где можно основательно почитать про то, как делать ассемблерные вставки в C/C++.
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
11.11.2009, 16:10 #19
Лучший ответ Сообщение было отмечено как решение

Решение

По поводу inline'а лучше поясню на более конкретном примере. Допустим, мы имеем интерфейс для некоторых небольших действий. Что-то мудрённое писатьне будем, а ограничимся операциями сложения и вычитания (чтобы меньше было в коде текста и проще было понять суть). Пусть интерфейсы называются asm_add и asm_sub соотвественно. Таким образом мы реализуем некие кубики, из которых можно будет строить более объёмные блоки. В данном примере в качестве блока реализуем функцию func от трёх параметров, которая реализует свёртку "x+y-z"

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Файл t.h */
 
static inline int
asm_add (int src1, int src2)
{
  register int dst;
 
  asm ("addl %2, %0" : "=&r" (dst) : "0" (src1), "r" (src2));
 
  return dst;
}
 
static inline int
asm_sub (int src1, int src2)
{
  register int dst;
 
  asm ("subl %2, %0" : "=&r" (dst) : "0" (src1), "r" (src2));
 
  return dst;
}
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* Файл t.c */
 
#include <stdio.h>
#include "t.h"
 
int
func (int x, int y, int z)
{
  int a, b;
  
  a = asm_add (x, y);
  b = asm_sub (a, z);
  
  return b;
}
В итоге, имеем следующий код:

Код
$ gcc t.c -O2 -S
$ cat t.s
        .file   "t.c"
        .text
        .p2align 4,,15
.globl func
        .type   func, @function
func:
        pushl   %ebp
        movl    %esp, %ebp
        movl    12(%ebp), %edx
        movl    16(%ebp), %ecx
        movl    8(%ebp), %eax
        popl    %ebp
#APP
        addl %edx, %eax
        subl %ecx, %eax
#NO_APP
        ret
        .size   func, .-func
        .ident  "GCC: (GNU) 4.1.2 (Gentoo 4.1.2 p1.1)"
        .section        .note.GNU-stack,"",@progbits
В итоге компилятор все наши static inline процедуры подставил (а коды самих процедур удалил) и мы получили "быструю" функцию func, в которой функциональная часть - это две наши операции addl и subl, всё остальное - это работа по перенесению параметров из стека на регистр и сохранение frame-pointer'а. Если бы мы функции asm_add и asm_sub написале в виде процедур на ассемблере в отдельном ассемблерном файле, то компилятор бы подстановку в принципе не смог сделать и быстрый "блок из кубиков" реализовать бы не получилось

В данном случае весь интерфейс у нас реализован в виде процедур на языке GNU-C, который другие компиляторы не понимают. При использовании другого компилятора нам бы нужно было подхачить только "кубиковый" файл t.h и как-то на языке или каким-либо другим способом написать функции, которые выполняют нужные действия. Пусть они будут не на ассемблере, пусть они получатся медленными, но мы исправили только самый нижний уровень, не трогая при этом весь остальной код. В итоге программу заставили работать, пусть и медленнее, чем можно было бы, но для первого шага этого оказалось бы достаточно. Этот абзац уже относится не столько к ассемблерным вставкам, сколько к технике программирования и реализации архитектурно-зависимых частей в виде маленьких кубиков

Добавлено через 1 минуту
Цитата Сообщение от RNT Посмотреть сообщение
Подскажите пожалуйста книжки или статьи, где можно основательно почитать про то, как делать ассемблерные вставки в C/C++.
Анус состоит в том, что по этому поводу по большому счёту нигде нет внятной литературы. Есть техническая документация по gcc, но она слишком ублюдочная. Это хорошая тема для FAQ'а, но чтоды описать доступно, надо будет попотеть и придумать хотя бы с какого боку начать пояснения. Я имею в виду gcc. А общего механизма нет, в каждом компиляторе он реализован по-своему
3
RNT
Автор FAQ
3138 / 358 / 3
Регистрация: 08.08.2009
Сообщений: 1,126
11.11.2009, 16:15  [ТС] #20
Цитата Сообщение от Evg Посмотреть сообщение
Анус состоит в том, что по этому поводу по большому счёту нигде нет внятной литературы.
Evg, а как ты это изучил ?
0
11.11.2009, 16:15
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.11.2009, 16:15
Привет! Вот еще темы с решениями:

Ошибка компиляции
#include &lt;iostream.h&gt; ...

Ошибка компиляции
Помогите, не могу понять в чем проблема. При компиляции вылетает ошибка: ...

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

Ошибка при компилировании ассемблерной вставки
При попытки добавить ассемблерную вставку выдается ошибка: unit1.pas(31,3)...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru