Писал программу для перевода чисел из DEC в HEX и наоборот разными функциями на Windows с помощью MVS, теперь пришла пора перенести программу на линукс, однако я встретился с неразрешимой проблемой.
/usr/bin/ld: ./Source.o: relocation R_X86_64_32S against undefined symbol `n' can not be used when making a PIE object; перекомпилируйте с параметром -fPIC Компилировать через консоль с параметром -fPIC проблвал, не помогло, в настройках проекта параметр указывал.
Кстати изначально программа была написана для х32 версии|, ещё на винде, а здесь убунта х64.
Версии: Ubuntu 18.04.3 LTS х64
g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Eclipse IDE for C/C++ Developers Version: 2019-09 R (4.13.0) Build id: 20190917-1200
Выкладываю код:
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
enum
{
CMD_FLOAT_TO_HEX,
CMD_DOUBLE_TO_HEX,
CMD_HEX_TO_FLOAT,
CMD_HEX_TO_DOUBLE,
CMD_EXIT
};
template<typename in, typename out>
out Asm1(in n) // FLOAT / DOUBLE -> HEX
{
out res;
asm
(
"fld n;"
"fstp res;"
);
return res;
}
template<typename in, typename out>
out Asm2(in n) // HEX -> FLOAT / DOUBLE
{
out res;
asm
(
"movsd %xmm0, n;"
"movsd res, %xmm0;"
);
return res;
}
template<typename in, typename out>
out Memcpy(in n)
{
out res;
memcpy(&res, &n, sizeof(in));
return res;
}
template<typename in, typename out>
out Cast(in n)
{
return *reinterpret_cast<out*>(&n);
}
template<typename in, typename out>
out Union(in n)
{
union
{
in _n;
out _res;
};
_n = n;
return _res;
}
int main()
{
int n;
cout << "<0> - float to hex" << endl;
cout << "<1> - double to hex" << endl;
cout << "<2> - hex to float" << endl;
cout << "<3> - hex to double" << endl;
cout << "<4> - exit" << endl << endl;
do
{
cout << "choose command (from 0 to 4): ";
cin >> n;
cout << endl;
switch (n)
{
case CMD_FLOAT_TO_HEX:
float f1;
cout << "write a number: ";
cin >> f1;
cout << "\na float number " << f1 << " in hex:\t0x" << hex << Memcpy<float, int>(f1) << " (MEMCPY)" << endl;
cout << "\t\t\t\t0x" << hex << Cast<float, int>(f1) << " (REINTERPRETER_CAST)" << endl;
cout << "\t\t\t\t0x" << hex << Union<float, int>(f1) << " (UNION)" << endl;
cout << "\t\t\t\t0x" << hex << Asm1<float, int>(f1) << " (__ASM) "<<endl;
cout << endl;
break;
case CMD_DOUBLE_TO_HEX:
double d1;
cout << "write a number: ";
cin >> d1;
cout << "\na double number " << d1 << " in hex:\t0x" << hex << Memcpy<double, long long>(d1) << " (MEMCPY)" << endl;
cout << "\t\t\t\t0x" << hex << Cast<double, long long>(d1) << " (REINTERPRETER_CAST)" << endl;
cout << "\t\t\t\t0x" << hex << Union<double, long long>(d1) << " (UNION)" << endl;
cout << "\t\t\t\t0x" << hex << Asm1<double, long long>(d1) << " (__ASM) " << endl;
cout << endl;
break;
case CMD_HEX_TO_FLOAT:
uint32_t f2;
cout << "write a hex: ";
cin >> hex >> f2;
cout << "\na hex 0x" << hex << f2 << " is equal to float\t" << Memcpy<int, float>(f2) << " (MEMCPY)" << endl;
cout << "\t\t\t\t\t" << Cast<int, float>(f2) << " (REINTERPRETER_CAST)" << endl;
cout << "\t\t\t\t\t" << Union<int, float>(f2) << " (UNION)" << endl;
cout << "\t\t\t\t\t" << Asm2<int, float>(f2) << " (__ASM) " << endl;
cout << endl;
break;
case CMD_HEX_TO_DOUBLE:
uint64_t d2;
cout << "write a hex: ";
cin >> hex >> d2;
cout << "\na hex 0x" << hex << d2 << " is equal to double\t" << Memcpy<long long, double>(d2) << " (MEMCPY)" << endl;
cout << "\t\t\t\t\t\t" << Cast<long long, double>(d2) << " (REINTERPRETER_CAST)" << endl;
cout << "\t\t\t\t\t\t" << Union<long long, double>(d2) << " (UNION)" << endl;
cout << "\t\t\t\t\t\t" << Asm2<long long, double>(d2) << " (__ASM) " << endl;
cout << endl;
break;
case CMD_EXIT:
break;
default:
cout << "wrong command" << endl;
cout << endl;
break;
}
} while (n != CMD_EXIT);
return 0;
}
Ассемблер в GCC так не работает.
Ассемблер в GCC не поддерживает прямого обращения к локальным переменным по именам. Всякий раз, когда вы пишете что-то вроде "fld n;"
, компилятор рассматривает это как обращение к глобальной переменной n
и передает его на рассмотрение линкеру. Линкер, разумеется, не находит никакой глобальной переменной n
, что и приводит к ошибке.
Локальные переменные нужно вручную описывать в ассемблерном блоке как входные и выходные операнды, через специальный синтаксис. См. пример здесь и документацию здесь.
Например
float Asm1(double n)
{
float res;
asm
(
"fldl %1;"
"fstps %0;"
: "=m" (res) : "m" (n)
);
return res;
}
При этом надежды на то, что в вашем исходном варианте ассемблерный код с fld
и fstp
поведет себя "по шаблонному" и будет генерировать правильную команду для каждого размера операнда не оправдались. В ассемблере GCC fld
и fstp
просто тупо эквивалентны flds
и fstps
. Для того, чтобы ваш шаблон с параметрами Asm1<double, float>
работал правильно, придется все равно явно указывать fldl
, как у меня в примере выше. То есть вся ваша затея с таким ассемблерным кодом внутри шаблона - не работает.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Пытаюсь сделать поиск участников из существующего файла, но отображает изначально непонятные цифры, в следствии чего как я подозреваю не дает...
Когда изучал строки и векторы, наткнулся на вывод вектора таким образом
Только начал заниматься с OpenGL и столкнулся с проблемами с тестом глубиныИспользую шейдеры для текстурированного GL_POLYGON и нескольких of GL_LINE_STRIP