Форум программистов, компьютерный форум, киберфорум
Наши страницы
Assembler: Linux
Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 24, средняя оценка - 4.92
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
#1

Встроенный ассемблер в linux - Assembler

26.11.2010, 10:33. Просмотров 3170. Ответов 18
Метки нет (Все метки)

Здравствуйте! Кому нибудь доводилось писать ассемблерные вставки в linux? (gcc или KDevelop или QTCreator - вроде одинаковый синтаксис). На чистом ассемблере все отлично получается, но на инлайн никак не пойму. В общем задача простая:
C
1
2
3
4
5
6
7
const float K = (float)(2*3.14159/(1<<30));
int main(int argc, char* argv[])
{
   unsigned int phase = 2000;
   float d = K*phase;
...
}
Дизассемблер выдал код:
http://www.cyberforum.ru/assembler/thread565034.html
Assembler
1
2
3
4
5
6
7
8
9
        14          d = K*phase;
0x08048a1f  <+267>:             mov    0x3c(%esp),%eax
0x08048a23  <+271>:             mov    $0x0,%edx
0x08048a28  <+276>:             mov    %eax,0x20(%esp)
0x08048a2c  <+280>:             mov    %edx,0x24(%esp)
0x08048a30  <+284>:             fildll 0x20(%esp)
0x08048a34  <+288>:             flds   0x8048c4c
0x08048a3a  <+294>:             fmulp  %st,%st(1)
0x08048a3c  <+296>:             fstps  0x54(%esp)
начал писать вставку:
C
1
2
3
4
5
6
7
//float d = K*phase;
asm("fildl $phase"); - не работает
asm("fildl %0" :: "g"(phase)); - так работает
// а со вторым множителем вообще никак
asm("flds $k"); - нет
asm("flds %0" :: "g"(K)); - тоже нет
asm("fmulp"); - нормально
ни с 'm' ни с каким другим ограничением целостности не работает.
Никто не подскажет как загрузить число (float) в сопроцессор?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.11.2010, 10:33
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Встроенный ассемблер в linux (Assembler):

Встроенный ассемблер. Как организовать цикл?
Необходимо составить простенькую программу, решение которой уже есть на Си....

Перенос программы под Linux: номера системных вызовов в DOS и Linux не совпадают
Здравствуйте, уважаемые программисты всея форума! Доброго вам времени суток! =)...

Встроенный Assembler в С++
Люди подскажите плиз, где я что-то не учёл В строке длиною не более 255...

Ассемблер
пример R=X!/2-2 при x=sp Добавлено через 2 часа 56 минут up up up

Ассемблер
Написать программы на Ассемблере. Помогите кто может))) Документ поврежден....

18
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
29.11.2010, 14:08  [ТС] #2
Всем спасибо за участие Вроде сделал, хоть и не красиво
0
Aye Aye
370 / 284 / 97
Регистрация: 17.12.2009
Сообщений: 567
05.12.2010, 05:20 #3
статья, и там еще одна где-то валяется, это так... на всякий случай )
1
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 09:40  [ТС] #4
Aye Aye, спасибо за ссылку, но там я тоже не нашел ответ. Проблема была в этом:
Assembler
1
2
flds   0x8048c4c // запись в стек сопроцессора значения, заданного адресом памяти
flds   0x54(%esp) // запись значения из кадра стека
первое мне так и не удалось, но так как второе без проблем - я просто создал еще одну локальную переменную
C
1
2
3
4
5
float _k = K;
asm("fildl %0" :: "g"(phase));
asm("flds %0" :: "g"(_k));
asm("fmulp");
asm("fstps %0" : "=g"(d));
поэтому я написал что сделал, но некрасиво
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
05.12.2010, 11:54 #5
Я понимаю, как работать с gnu'тыми вставками, но я практически не знаю intel'овской системы команд. Если чётко пояснишь, что должно быть, то могу попробовать. В первую очередь интересует описание самой вставки: где там операнды входные, где выходные, что является регистром, а что - обращением в память

Добавлено через 2 минуты
Проблема с gnu'тыми вставками такая, что нигде нет внятного описания. Вот, например, родное описание.
http://gcc.gnu.org/onlinedocs/gcc-4....l#Extended-Asm
1
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 14:05  [ТС] #6
Цитата Сообщение от Evg Посмотреть сообщение
Если чётко пояснишь, что должно быть
коротко: как загрузить в сопроцессор константу?
C
1
2
3
4
5
6
7
8
9
10
11
12
13
const float K = 3.14159; // вот эту
int main(int argc, char* argv[])
{
    float _k = K;
// это дизассемблер показывает так:
// mov $0x31c90fd0, %eax - то есть адрес памяти, где расположена K = 0x31c90fd0
// mov %eax, 0x38(%esp)
// теперь я могу загрузить в сопроцессор _k
asm("flds %0" :: "g"(_k));
// генерируется инструкция:
// flds 0x38(%esp)
...
}
а как мне загрузить непосредственно К, т.е. чтобы сенерировалось
Assembler
1
flds   0x31c90fd0
я не понял.
Спасибо за ссылку, буду разбираться
0
Goodwin98
2521 / 817 / 10
Регистрация: 31.05.2009
Сообщений: 1,672
05.12.2010, 14:13 #7
Цитата Сообщение от vital792 Посмотреть сообщение
а как мне загрузить непосредственно К, т.е. чтобы сенерировалось
Разве существует такой опкод ? По идее это только через отдельную переменную и делается.
0
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 14:19  [ТС] #8
Команда:
FLD источник
Назначение:
Загрузить вещественное число в стек
Процессор:
8087
Команда помещает содержимое источника (32-, 64- или 80-битная переменная или ST(n))
надо загрузить не из кадра стека функции, а из памяти. Как то же это делает компилятор?
Цитата Сообщение от vital792 Посмотреть сообщение
Дизассемблер выдал код:
Код ASM
14* * * * * * * d = K*phase;
0x08048a1f *<+267>: * * * * * * mov * *0x3c(%esp),%eax
0x08048a23 *<+271>: * * * * * * mov * *$0x0,%edx
0x08048a28 *<+276>: * * * * * * mov * *%eax,0x20(%esp)
0x08048a2c *<+280>: * * * * * * mov * *%edx,0x24(%esp)
0x08048a30 *<+284>: * * * * * * fildll 0x20(%esp)
0x08048a34 *<+288>: * * * * * * flds * 0x8048c4c
0x08048a3a *<+294>: * * * * * * fmulp *%st,%st(1)
0x08048a3c *<+296>: * * * * * * fstps *0x54(%esp)
в смысле мне не число непосредственное загрузить а с адреса памяти
0
Goodwin98
2521 / 817 / 10
Регистрация: 31.05.2009
Сообщений: 1,672
05.12.2010, 14:23 #9
Цитата Сообщение от vital792 Посмотреть сообщение
в смысле мне не число непосредственное загрузить а с адреса памяти
Не правильно понял этот синтаксис

Добавлено через 1 минуту
Цитата Сообщение от vital792 Посмотреть сообщение
надо загрузить не из кадра стека функции, а из памяти. Как то же это делает компилятор?
В первом посте константа глобальная. И поэтому она располагается в сегменте данных, а не в стеке.
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
05.12.2010, 14:28 #10
При твоём варианте написания программы - никак. И дело тут не в возможности ассемблерной вставки, а в том, что у тебя имеется переменная, а ты хочешь получить константу. Такое можно сделать ТОЛЬКО в варианте с оптимизациями

C
1
2
3
4
5
6
const float K = 3.14159;
 
void func (void)
{
  asm ("flds %0" : : "i"(K));
}
Код
$ gcc -O2 t.c -S
$ cat t.s
...
	flds $0x40490fd0
...
Такой вариант неправильный по двум причинам:
1. "i" означает "immediate" (грубо говоря, константу). Превратить переменную в константу компилятор может только в режиме с оптимизациями
2. Насколько я знаю, такая операция портит какой-то регистр. Я точно не знаю, но, возможно, это st(1). Нужно его добавить в constraint's - пример есть в самом конце по ссылке из поста #5

Можно сделать другой вариант и вместо переменной использовать явную константу (через макрос). Тогда такой вариант будет работать как в оптимизациях, так и без них.

C
1
2
3
4
5
6
#define K 3.14159f
 
void func (void)
{
  asm ("flds %0" : : "i"(K));
}
Но это "тупое" решение "в лоб". На самом деле надо это делать честно и корректным образом описывать то, что делается в вставке (чтобы компилятор знал это и правильно учитывал внутри большого фрагмента кода). Проблема в том, что я не знаю, как вся эта плавающая хренотень работает в intel'е. По ссылке из поста #3 есть описание

"t" : First (top of stack) floating point register
"u" : Second floating point register
и надо работать именно через эти конструкции. Если ты хотя бы на пальцах мне пояснишь работу этого плавающего стека, то может и смогу тебе правильно написать вставку
1
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 14:29  [ТС] #11
Цитата Сообщение от Goodwin98 Посмотреть сообщение
И располагается она в сегменте данных, а не в стеке.
именно. И в этом есть загвоздка - как оттуда его загрузить? Ведь без вставок все прекрасно получается - и в intel и в at&t вариантах. А с этими непонятными ограничителями целостности, сколько ни пытался не смог. Вообще эта проблема решена, как я писал выше, и это уже не так важно, просто интерес остался
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
05.12.2010, 14:32 #12
Вот например:

Код
Here are a couple of reasonable asms to want to write. This asm takes one input, which is internally popped, and produces two outputs.

     asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));

This asm takes two inputs, which are popped by the fyl2xp1 opcode, and replaces them with one output. 
The user must code the st(1) clobber for reg-stack.c to know that fyl2xp1 pops both inputs.

     asm ("fyl2xp1" : "=t" (result) : "0" (x), "u" (y) : "st(1)");
Объясни мне, что делают операции fsincos и fyl2xp1 (т.е. откуда читают и куда пишут)

Добавлено через 1 минуту
А так же, где допустимы только регистры, а где регистры и константы
0
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 14:38  [ТС] #13
Evg, прикольно не думал что все так плохо Спасибо за помощь, но на работе этот вопрос закрыли - даже переписанный на ассемблер код не успевал генерировать сигнал и решили упрощать алгоритм (этот код использовался для генерации синуса со сложной фазовой манипуляцией) - так что думаю можно и здесь закрывать обсуждение. Я думал решение где то на поверхности, в одной строчке
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
05.12.2010, 14:43 #14
Решение на самом деле на поверхности. И там всё просто. Но я не могу тебе это решение сказать, потому что не знаю, как работает intel'овский процессор. Т.е. я могу читать и понимать документацию по gcc или его исходники, но для этого нужно понимать, как процессор работает

Добавлено через 2 минуты
Хотя, когда вопрос закрыт, у людей обычно уже нет энтузиазма для выяснения того, как же на самом деле правильно делать. Если работа разовая - забей. Если потребуется в будующем - лучше один раз разберись по нормальному
0
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 14:46  [ТС] #15
Цитата Сообщение от Evg Посмотреть сообщение
fsincos
Вычисляет синус и косинус числа, находящегося в st(0), помещает синус в st(0) и затем помещает косинус в стек, синус оказывается в st(1), косинус — в st(0)

Цитата Сообщение от Evg Посмотреть сообщение
fyl2xp1
Вычисление у*log2(x+1), то есть st(1)*log2(st(0)+1). результат в st(0)
Перед обоими командами надо загрузить в стек аргументы этих вычислений командой fld

Добавлено через 1 минуту
Цитата Сообщение от Evg Посмотреть сообщение
fsincos и fyl2xp1
обе команды выполняют вычисления в стеке сопроцессора, с памятью не обмениваются

Добавлено через 1 минуту
Цитата Сообщение от Evg Посмотреть сообщение
Если работа разовая - забей. Если потребуется в будующем - лучше один раз разберись по нормальному
очень надеюсь что не пригодится больше, но мало ли как случится... поэтому пытаюсь разобраться пока время есть
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
05.12.2010, 15:00 #16
Ладно... проще забить. Потому что такое описание мне толком ничего не дало. Ну или если взять конкретный пример

C
1
2
3
4
5
6
float sin, cos, inp;
 
void func (void)
{
  asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));
}
то сгенерится код:

Код
	flds	inp
	fsincos
	fstps	cos
	fstps	sin
Что этот код делает? Мне нужно понять, чтобы связать код и исходник. Не в общих словах типа "загружает данные не регистры и вычисляет синус и косинус", а конкретно, что откуда и куда грузится. знаю, что тут используются регистры %st(0) и %st(1), но я не вижу их в коде. Я не понимаю дебильной интеловской системы команд, где пишется операция, которая неявно что-то читает или пишет. Интуитивно я понимаю, что %st(0) и %st(1) - это какие-то элементы некоторого аппаратного регистрового стека, но конкретного понимания нет

Добавлено через 6 минут
Да, вот ещё. Если я это дело правильно понимаю, то flds - сама по себе операция НЕзаконченная. Т.е. сама по себе в воздухе она не нужна. Она нужна только вместе с другими операциями. Так вот все эти операции вместе должны находиться в одной вставке (а не в разных), потому что с точки зрения языка значения аргументов между вставками можно передавать только через языковые переменные. Есть конечно специальные финты для обхода этого ограничения, но лучше писать код без финтов.

Конкретно с синусом и косинусом мы можем объявить аргумент константой

C
1
2
3
4
5
6
7
float sin, cos;
const float inp = 1.23;
 
void func (void)
{
  asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));
}
и получить код


Код
	flds	.LC0  <-- а вот и flds
	fsincos
	fstps	cos
	fstps	sin
...
.LC0:
	.long	1067282596 <--- а это наша константа
Я правильно понимаю, что аргументом flds является адрес, откуда загружается значение?
1
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 15:10  [ТС] #17
Цитата Сообщение от Evg Посмотреть сообщение
Что этот код делает? Мне нужно понять, чтобы связать код и исходник. Не в общих словах типа "загружает данные не регистры и вычисляет синус и косинус", а конкретно, что откуда и куда грузится. знаю, что тут используются регистры %st(0) и %st(1), но я не вижу их в коде. Я не понимаю дебильной интеловской системы команд, где пишется операция, которая неявно что-то читает или пишет. Интуитивно я понимаю, что %st(0) и %st(1) - это какие-то элементы некоторого аппаратного регистрового стека, но конкретного понимания нет
чтобы это понять проще всего смотреть изменение стека в отладчике
flds inp // inp загружается на вершину стека (в st(0))
fsincos // в st(0) косинус в st(1) синус
fstps cos // выталкивает из st(0) в переменную cos, теперь st(0) - синус
fstps sin // выталкивает из st(0) в переменную sin
Добавлено через 3 минуты
Цитата Сообщение от Evg Посмотреть сообщение
flds - сама по себе операция НЕзаконченная. Т.е. сама по себе в воздухе она не нужна
Цитата Сообщение от Evg Посмотреть сообщение
Я правильно понимаю, что аргументом flds является адрес, откуда загружается значение?
правильно. Аргумент fld или адрес памяти, или регистр сопроцессора. Во втором случае его содержимое копируется на вершину стека
0
Evg
Эксперт CАвтор FAQ
18937 / 6898 / 512
Регистрация: 30.03.2009
Сообщений: 19,432
Записей в блоге: 30
05.12.2010, 15:14 #18
Хорошо. Конкретного ответа, скорее всего, я не добьюсь. Но будем считать, что условно я понял всю эту хероментию с плавающим стеком. Н, насколько понял, операция flads - это операция ЧТЕНИЯ ИЗ ПАМЯТИ, но НЕ операция ПЕРЕСЫЛКИ КОНСТАНТЫ.

Объясни ещё раз постановку задачи. Т.е. то, что у тебя написано в первом посте. Что ты хочешь сделать? Написать при помощи ассемблерной вставки некий чёрный ящик, на вход которому подаём целочисленное phase и плавающее K, а на выходе получаем величину ((float)phase * K)?

Добавлено через 1 минуту
Цитата Сообщение от vital792 Посмотреть сообщение
или регистр сопроцессора
А можно про это дело подробнее. В очередной раз говорю: я не знаю intel'овскую систему команд. И хочется напомнить, что правильно поставленный вопрос - это уже половина ответа
0
vital792
1997 / 1269 / 60
Регистрация: 05.06.2010
Сообщений: 2,213
05.12.2010, 15:26  [ТС] #19
Цитата Сообщение от Evg Посмотреть сообщение
Хорошо. Конкретного ответа, скорее всего, я не добьюсь.
да, у меня есть некоторые проблемы с этим. В преподаватели меня точно не возьмут

Цитата Сообщение от Evg Посмотреть сообщение
насколько понял, операция flads - это операция ЧТЕНИЯ ИЗ ПАМЯТИ, но НЕ операция ПЕРЕСЫЛКИ КОНСТАНТЫ
это команда пересылки данных. Операндом может быть 32-, 64- или 80-битная переменная, или регистр сопроцессора. Сопроцессор содержит восемь регистров для хранения данных. Регистры данных не адресуются по именам, как регистры основного процессора. Вместо этого эти восемь регистров рассматриваются как стек, вершина которого называется ST, а более глубокие элементы — st(1), st(2) и до st(7). То есть непосредственно к регистрам обращаться нельзя(если не использовать MMX)

Цитата Сообщение от Evg Посмотреть сообщение
Объясни ещё раз постановку задачи. Т.е. то, что у тебя написано в первом посте. Что ты хочешь сделать? Написать при помощи ассемблерной вставки некий чёрный ящик, на вход которому подаём целочисленное phase и плавающее K, а на выходе получаем величину ((float)phase * K)?
ну вообще меня ответы выше вполне удовлетворили, собственно вопрос изначальный исчерпан
0
05.12.2010, 15:26
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
05.12.2010, 15:26
Привет! Вот еще темы с решениями:

ассемблер
Помогите решить 3 задачи на ассемблере 1. Даны двузначные числа m и n в...

ассемблер + си
пишу на ассемблере и тестирую на си. вот часть кода: const int n=7; int...

Ассемблер
Добрый день, уважаемые программисты! На данный момент в нашем университете...

Ассемблер vs С++
Доброго времени суток. Я только начал изучать ассемблер. 1. Скажите, будут ли...


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

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

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