Re: Определить l/r endian в runtime
От: Pzz Россия https://github.com/alexpevzner
Дата: 23.12.08 18:22
Оценка: 5 (2) +2
Здравствуйте, nen777w, Вы писали:

N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?


Понятие endian'а имеет смысл только для платформ, на которых целочисленные типы имеют побайтовое представление. Не всякая платформа такова. Например, у машины БЭСМ-6 адресовались 48-битные слова, а отдельные байты не адресовались.

С этой оговоркой, для целых можно определить endian следующим образом: взять соответствующего размера целое, скопировать в него побайтово последовательность 0x01, 0x02, ..., посмотреть, что получилось. При этом надо понимать, что для 4-байтовых целых теоретически возможны все 24 перестановки, хотя на практике как правило используются только две, известные как big и little endian.

Форматы представления плавающих чисел отличаются не только порядком байт, но и тем, например, сколько и в каком месте бит отведено на хранение мантисы и порядка, и как эти биты интерпретируются. К счастию, количество форматов, использующихся на практике, невелико, и их можно все последовательно перебрать.

Что такое endian для указателей, не вполне понятно. Но практической ценности ответ на этот вопрос не несет, т.к. указатели бессмысленно передавать между машинами: на получателе он не будет указывать ни в какое разумное место. Если хочется передать структуру какого-то хитрозалинкованного объекта, то можно ссылаться либо на идентификаторы его запчастей, либо, если на принимающей стороне возможно воспроизвести их взаимное положение в памяти, на их смещения от некоторой общей базы. В таком случае вы будете иметь дели с целыми, а про них — см. выше.
Re[8]: Определить l/r endian в runtime
От: -MyXa- Россия  
Дата: 24.12.08 11:11
Оценка: 4 (1)
Здравствуйте, nen777w, Вы писали:

[поскипано]

N>надо правильно запихнуть в стек/регистры (в зависимости от конвенции вызова) аргументы для вызываемой функции.

N>Так как в ВМ своё представление чисел, то возникает задача, в каком порядке запихнуть байты в стек например для типа long? от малого к большому или от большого к малому.

Если я Вас правильно понял, то Вы так прям и будете натурально сами руками класть значения в стек (для MessageBox, например)? Не делайте этого. Пусть компилятор сам разбирается — ему же лучше знать. Вот Вам велосипед для примера:

struct base_variable
{
    virtual ~base_variable() = 0 {};
};

template<typename T>
struct basic_variable : base_variable
{
    basic_variable()
        : val_()
    {
    }

    explicit basic_variable(T v)
        : val_(v)
    {
    }

    T val() const
    {
        return val_;
    }
private:
    T val_;
};

struct base_caller
{
    typedef boost::shared_ptr<base_variable> bv;
    typedef std::stack<bv> vs;

    virtual void call(vs & s) = 0;
};

template<typename T>
struct basic_caller;

template<typename R>
struct basic_caller<R()> : base_caller
{
    basic_caller(R (*f_)())
        : f(f_)
    {
    }

    void call(vs & s)
    {
        if (s.size() != 0)
        {
            throw std::invalid_argument("");
        }
        s.push(boost::shared_ptr<base_variable>(new basic_variable<R>(f())));
    }
private:
    R (*f)();
};

template<typename R, typename P1>
struct basic_caller<R (P1)> : base_caller
{
    basic_caller(R (*f_)(P1))
        : f(f_)
    {
    }

    void call(vs & s)
    {
        if (s.size() != 1)
        {
            throw std::invalid_argument("");
        }
        boost::shared_ptr<basic_variable<P1> > p1(boost::shared_dynamic_cast<basic_variable<P1> >(s.top()));
        s.pop();

        s.push(boost::shared_ptr<base_variable>(new basic_variable<R>(f(p1->val()))));
    }
private:
    R (*f)(P1);
};

template<typename R, typename P1, typename P2>
struct basic_caller<R (P1, P2)> : base_caller
{
    basic_caller(R (*f_)(P1, P2))
        : f(f_)
    {
    }

    void call(vs & s)
    {
        if (s.size() != 2)
        {
            throw std::invalid_argument("");
        }
        boost::shared_ptr<basic_variable<P1> > p1(boost::shared_dynamic_cast<basic_variable<P1> >(s.top()));
        s.pop();
        boost::shared_ptr<basic_variable<P2> > p2(boost::shared_dynamic_cast<basic_variable<P2> >(s.top()));
        s.pop();

        s.push(boost::shared_ptr<base_variable>(new basic_variable<R>(f(p1->val(), p2->val()))));
    }
private:
    R (*f)(P1, P2);
};

long foo0(){ return 1; }
double foo1(char){ return 1.1; }
int foo2(int, char) { return 42; }

int main(int argc, char* argv[])
{
    std::map<std::string, base_caller*> all_functions;
    all_functions["foo2"] = new basic_caller<int (int, char)>(&foo2);
    
    base_caller::vs stack;
    stack.push(boost::shared_ptr<basic_variable<char> >(new basic_variable<char>()));
    stack.push(boost::shared_ptr<basic_variable<int> >(new basic_variable<int>()));
    

    all_functions["foo2"]->call(stack);


Тут, правда, не хватает работы со ссылками/константами и нет поддержки конвенций, отличных от дефолтной. Ещё можно сделать всяких мейкеров, чтоб инстансы basic_caller дедьюсить, можно нагородить генерацию кода с помощью Boost.Preprocessor, можно, вообще, всё это выбросить и поюзать Boost.Fusion, только не пихайте параметры в стек сами.
Если не поможет, будем действовать током... 600 Вольт (C)
Re[9]: Определить l/r endian в runtime
От: 8bit  
Дата: 24.12.08 12:24
Оценка: 4 (1)
ВМ может не знать интерфейса функции во время компиляции.
Во время выполнения она конечно может восстановить интерфейс по сигнатуре функции,
но тогда параметры темлейта basic_caller надо будет сформировать динамически. Как это сделать?
Вообщем придется делать велосипед который уже написан:
Для всех этих вещей есть библиотека libffi. wiki
Но даже с ней будет медленно.
Поэтому таки да, люди вручную переписывают на ассемблере и вручную кладут на стек все что надо.
Например в гуглоандройдовском дальвике так сделано.
Re[12]: Определить l/r endian в runtime
От: 8bit  
Дата: 24.12.08 17:41
Оценка: 4 (1)
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, nen777w, Вы писали:


N>>Мда.. Интересная либа. Спасибо.

N>>То что MacOSX ppc и x86 совместимая это вообще супер.
N>>А Вы не в курсе случайно как её собрать под win32 что бы пощупать?

msys + mingw

Погляди еще на cinvoke, она в wiki тоже упоминается.
У неё есть проект/солюшн для студии.

Pzz>В макоси эта совместимость достигается тем, что каждый "универсальный" исполняемый файл и/или библиотека содержит в действительности внутри себя два совершенно независимых комплекта кода: для x86 и для ppc. При этом ppc у них big endian (хотя их процессор умеет работать в обеих режимах, но в свое время они выбрали big endian, видимо для совместимости с motorola 68000, на котором еще самые первые маки были сделаны), а x86, естественно, little endian, поскольку по-другому он не умеет.


nen777w имел ввиду что libffi портированна на ppc и x86 и другие процессоры.
universal binary здесь не причем
Re: Определить l/r endian в runtime
От: johny5 Новая Зеландия
Дата: 08.01.09 04:54
Оценка: 3 (1)
Можно ещё без указателемагии:

bool isLittleEndian()
{
union
{
unsigned in;
unsigned char[sizeof(unsigned)] out;
} test;

test.in = 1;

return test.out[0] != 0;
}

По мне так смотрится безопаснее.
Re: Определить l/r endian в runtime
От: Conr Россия  
Дата: 23.12.08 18:23
Оценка: +1
Здравствуйте, nen777w, Вы писали:

N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?

N>Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).

bool is_bigendian()
{
    const int t = 1;
    return (*(char*)&t) == 0;
}


Да и вообще почитать полезно: http://www.ibm.com/developerworks/aix/library/au-endianc/index.html?ca=drs-
Re: Определить l/r endian в runtime
От: MasterZiv СССР  
Дата: 24.12.08 06:54
Оценка: -1
nen777w пишет:

> Есть ли способ в runtime кроссплатформенно, для любого С/С++

> компилятора, определить l/r endian для всех интегральных типов, включая
> указатель?

В рантайме ты ничего не определишь. Там уже надо знать.
В компайл-тайме есть autoconf/configure
Posted via RSDN NNTP Server 2.1 beta
Определить l/r endian в runtime
От: nen777w  
Дата: 23.12.08 17:09
Оценка:
Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?
Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).
Второй не менее тупой, что то вроде (код писал прямо на месте):

 long l = 10;
_asm {
  push l;  
}
 byte check;
   _asm {
     pop check;
   }
   if( check = 10 )
   {
     //left endian
   } 
   else
   {
     //right endian
   }


Что мне тоже не нравится так как это сделать с float Я пока не в курсе, разве что сравнивать с заранее подготовленным шаблоном.

p.s.
Сори если вопрос покажется глупым. Возможно я не всё ещё понимаю до конца правильно.
l/r endian
Re: Определить l/r endian в runtime
От: Vamp Россия  
Дата: 23.12.08 17:11
Оценка:
Во-первых, хорошо бы пользоваться общепринятыми именованиями. Оконечность — она бывает большая и малая, а не правая и левая. Во-вторых, не могу себе представить, для какой задачи это может быть нужно?
Да здравствует мыло душистое и веревка пушистая.
Re[2]: Определить l/r endian в runtime
От: nen777w  
Дата: 23.12.08 17:15
Оценка:
Здравствуйте, Vamp, Вы писали:

V>Во-первых, хорошо бы пользоваться общепринятыми именованиями. Оконечность — она бывает большая и малая, а не правая и левая.


Ок. Договоримся. Пусть будет так.

Во-вторых, не могу себе представить, для какой задачи это может быть нужно?

Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).
Re[3]: Определить l/r endian в runtime
От: Vamp Россия  
Дата: 23.12.08 17:24
Оценка:
N>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).
Непонятно. А зачем оконечность-то знать? Если преполагается, что функция может исполняться на машине с произвольной архитектурой и вызывается удаленно, то оконечность при передаче должна быть network.
Да здравствует мыло душистое и веревка пушистая.
Re[4]: Определить l/r endian в runtime
От: nen777w  
Дата: 23.12.08 17:28
Оценка:
Здравствуйте, Vamp, Вы писали:

N>>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).

V>Непонятно. А зачем оконечность-то знать? Если преполагается, что функция может исполняться на машине с произвольной архитектурой и вызывается удаленно, то оконечность при передаче должна быть network.

ВМ — это виртуальная машина. Т.е. виртуальный процессор исполняющий байткод. А оконечность нужно знать что бы правильно положить в стек аргументы при вызове "внешней функции" согласно её конвенции.
Re: Определить l/r endian в runtime
От: Аноним  
Дата: 23.12.08 17:29
Оценка:
N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?

bool IsLittleEndian ()
{
    int littleEndian = true;
    return *((char*)&littleEndian);
}
Re[5]: Определить l/r endian в runtime
От: Vamp Россия  
Дата: 23.12.08 17:30
Оценка:
N>ВМ — это виртуальная машина. Т.е. виртуальный процессор исполняющий байткод. А оконечность нужно знать что бы правильно положить в стек аргументы при вызове "внешней функции" согласно её конвенции.
Если это виртуальный процессор, то его оконченость ты определяешь сам. Нет, чего-то я не понимаю.
Да здравствует мыло душистое и веревка пушистая.
Re[6]: Определить l/r endian в runtime
От: MasterZiv СССР  
Дата: 24.12.08 06:55
Оценка:
Vamp пишет:
> Нет, чего-то я не понимаю.
+1. Чего-то он странного хочет.
Posted via RSDN NNTP Server 2.1 beta
Re[7]: Определить l/r endian в runtime
От: nen777w  
Дата: 24.12.08 09:37
Оценка:
MZ>Vamp пишет:
>> Нет, чего-то я не понимаю.
MZ>+1. Чего-то он странного хочет.

Да ничего странного. Есть виртуальная машина а есть "внешние" по отношению к ВМ функции, ну например WinAPI функция из DLL — MessageBox().
У ВМ свое собственное, отличное от x386 представление чисел. В ассемблере ВМ существует команда ECALL — т.е. вызов внешней функции, описание этой функции (её адрес, конвенция, указатель, возвращаемое значение, порядок аргументов и их типов) лежат в специальной таблице.
И в какой то момент в байткоде ВМ возникает команда ECALL грубо говоря с номером в таблице где храниться описание. Так как код выполняющий инструкции ВМ это обычный x386 код, то возможность вызвать внешнюю (по отношению к байткоду ВМ) функцию нет никаких проблем, единственное что, так это надо правильно запихнуть в стек/регистры (в зависимости от конвенции вызова) аргументы для вызываемой функции.
Так как в ВМ своё представление чисел, то возникает задача, в каком порядке запихнуть байты в стек например для типа long? от малого к большому или от большого к малому.

Или Я плохо понял как нужно строить ВМ (потому что большую часть додумывал сам) или я уже не знаю как объяснить
Re[8]: Определить l/r endian в runtime
От: 8bit  
Дата: 24.12.08 10:02
Оценка:
Здравствуйте, nen777w, Вы писали:

Не надо определять endian в runtime.
Под дефайнами два разных варианта сделай. И сделай два билда.
Никому это в runtime не нужно, только тормозить будет.
Re[9]: Определить l/r endian в runtime
От: nen777w  
Дата: 24.12.08 10:18
Оценка:
8>Не надо определять endian в runtime.
8>Под дефайнами два разных варианта сделай. И сделай два билда.
8>Никому это в runtime не нужно, только тормозить будет.

Ну я собственно уже разобрался, спасибо товарищам из RSDN.
Re: Определить l/r endian в runtime
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 24.12.08 13:56
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?

N>Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).

В runtime, как уже было сказанно, не проблема. Способы описанны выше. Только зачем определять в runtime когда в Boost уже это определенно для Compile-Time, см. BOOST_LITTLE_ENDIAN, BOOST_BIG_ENDIAN и т.п. в файле boost/detail/endian.hpp.
getboost.codeplex.com
citylizard.codeplex.com
boost endian cpp compile-time
Re[2]: Определить l/r endian в runtime
От: MShura  
Дата: 24.12.08 15:48
Оценка:
_>В runtime, как уже было сказанно, не проблема. Способы описанны выше. Только зачем определять в runtime когда в Boost уже это определенно для Compile-Time, см. BOOST_LITTLE_ENDIAN, BOOST_BIG_ENDIAN и т.п. в файле boost/detail/endian.hpp.

Все сводится либо к внешнему #define либо к зависимости от типа процессора
Перевести внешний #define во внутренний не трудно и без boost
А зависимость от типа процессора неоднозначная:
есть такие процессоры (например TMS320C6713), endianness которых меняется одним нажатием кнопочки.
Re[10]: Определить l/r endian в runtime
От: nen777w  
Дата: 24.12.08 16:18
Оценка:
8>Вообщем придется делать велосипед который уже написан:
8>Для всех этих вещей есть библиотека libffi. wiki

Мда.. Интересная либа. Спасибо.
То что MacOSX ppc и x86 совместимая это вообще супер.
А Вы не в курсе случайно как её собрать под win32 что бы пощупать?
Re[11]: Определить l/r endian в runtime
От: Pzz Россия https://github.com/alexpevzner
Дата: 24.12.08 16:30
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Мда.. Интересная либа. Спасибо.

N>То что MacOSX ppc и x86 совместимая это вообще супер.
N>А Вы не в курсе случайно как её собрать под win32 что бы пощупать?

В макоси эта совместимость достигается тем, что каждый "универсальный" исполняемый файл и/или библиотека содержит в действительности внутри себя два совершенно независимых комплекта кода: для x86 и для ppc. При этом ppc у них big endian (хотя их процессор умеет работать в обеих режимах, но в свое время они выбрали big endian, видимо для совместимости с motorola 68000, на котором еще самые первые маки были сделаны), а x86, естественно, little endian, поскольку по-другому он не умеет.
Re[2]: Определить l/r endian в runtime
От: Аноним  
Дата: 25.12.08 07:47
Оценка:
Здравствуйте, Conr, Вы писали:

C>Здравствуйте, nen777w, Вы писали:


N>>Есть ли способ в runtime кроссплатформенно, для любого С/С++ компилятора, определить l/r endian для всех интегральных типов, включая указатель?

N>>Пока что у меня на уме два способа, первый простой — переложить это на пользователя посредством определения соответствующего define, но это потребует открытия исходного кода библиотеки (либо её части).

C>
C>bool is_bigendian()
C>{
C>    const int t = 1;
C>    return (*(char*)&t) == 0;
C>}
C>


C>Да и вообще почитать полезно: http://www.ibm.com/developerworks/aix/library/au-endianc/index.html?ca=drs-


я бы написал так, приведение указателей нарушает strict aliasing, да и код не очень отражает
что же происходит на самом деле:
union {
        long val;
        unsigned char bytes[sizeof(long)];
    } test;
    test.val = 1;
    if (test.bytes[0] == 1) {
        printf("little endian\n");
    } else
        printf("big endian\n");
Re[2]: Определить l/r endian в runtime
От: Аноним  
Дата: 25.12.08 07:59
Оценка:
Здравствуйте, MasterZiv, Вы писали:

MZ>nen777w пишет:


>> Есть ли способ в runtime кроссплатформенно, для любого С/С++

>> компилятора, определить l/r endian для всех интегральных типов, включая
>> указатель?

MZ>В рантайме ты ничего не определишь. Там уже надо знать.

MZ>В компайл-тайме есть autoconf/configure

Это шутка?

Если посмотреть какже autconf/configure определят little/big endian

то можно увидедть что она компилирует с программу типа


int
main ()
{

  /* Are we little or big endian?  From Harbison&Steele.  */
  union
  {
    long int l;
    char c[sizeof (long int)];
  } u;
  u.l = 1;
  return u.c[sizeof (long int) - 1] == 1;

  ;
  return 0;
}


а исходя из того что вернет программа (определившая результат в runtime, заметьте),
configure определяет макрос типа HOST_ENDIASS
Re[13]: Определить l/r endian в runtime
От: nen777w  
Дата: 25.12.08 12:23
Оценка:
Пощупал cinvoke — либа просто супер!
Сделал небольшой тестовый проектик под WinXP и MacOSX x86 — работает!
А вот под MacOSX для ppc-таргета проблемы, gcc не понял asm инструкции для этого процессора!? хотя universal binnary из C/C++ кода собирать умеет. Во общему думаю надо будет взять и доработать напильником.
Re[10]: Определить l/r endian в runtime
От: -MyXa- Россия  
Дата: 25.12.08 13:27
Оценка:
Здравствуйте, 8bit, Вы писали:


8>ВМ может не знать интерфейса функции во время компиляции.


Что Вы имеете в виду? Зачем ей (мочь) знать интерфейс? В каких случаях она может не знать?

8>Во время выполнения она конечно может восстановить интерфейс по сигнатуре функции,


"интерфейс по сигнатуре"? В каком виде интерфейс и сигнатура?

8>но тогда параметры темлейта basic_caller надо будет сформировать динамически. Как это сделать?


Не параметры, а параметр. Это тип функции. Параметр темлейта basic_caller надо будет сформировать динамически _только_ тогда, когда у Вас появится динамически новый тип функции. Как Вы себе это представляете? Генерирование функций на лету?

М.б. Вы имеете в виду реализацию встроенной функции, наподобие writeln в паскале? Тогда можно добавить полную специализацию:

template<>
struct basic_caller<base_caller::bv(base_caller::vs&)> : base_caller
{
    basic_caller(base_caller::bv (*f_)(base_caller::vs&))
        : f(f_)
    {
    }

    void call(vs & s)
    {
        s.push(f(s));
    }
private:
    bv (*f)(base_caller::vs&);
};


И пусть уже автор сам мучается со стеком:

base_caller::bv writeln(base_caller::vs & s)
{
    ...
}


8>Вообщем придется делать велосипед который уже написан:

8>Для всех этих вещей есть библиотека libffi. wiki
8>Но даже с ней будет медленно.
8>Поэтому таки да, люди вручную переписывают на ассемблере и вручную кладут на стек все что надо.

Можно вручную положить параметры на стек быстрее, чем это делает компилятор?

8>Например в гуглоандройдовском дальвике так сделано.
Если не поможет, будем действовать током... 600 Вольт (C)
Re[11]: Определить l/r endian в runtime
От: 8bit  
Дата: 25.12.08 14:53
Оценка:
Здравствуйте, -MyXa-, Вы писали:

Если вы делаете скрипт\язык который имееть возможность расширяться native методами без перекомпиляции
самой VM (native методы например в dll), то ваш подход не подходит. Как вариант конечно можно заставить
каждый модуль сначала делать инициализацию своих методов.


MX>Можно вручную положить параметры на стек быстрее, чем это делает компилятор?

Да. Но я понимаю на что вы намекаете Не надо думать о "положить на стек" в буквальном смысле.
Вот ваш вариант будет медленно работать.
Re[8]: Определить l/r endian в runtime
От: minorlogic Украина  
Дата: 10.01.09 16:00
Оценка:
А пускай об этом вызывающая сторона позаботиться , она то нативная , ей проще.
... << RSDN@Home 1.2.0 alpha 4 rev. 1111>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[3]: Определить l/r endian в runtime
От: Mr.Cat  
Дата: 10.01.09 16:48
Оценка:
Здравствуйте, nen777w, Вы писали:
N>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).

Почему бы не хранить в байткоде VM все данные в network byte order и преобразовывать с помощью ntoh/hton в нативный порядок?
Re[4]: Определить l/r endian в runtime
От: Pzz Россия https://github.com/alexpevzner
Дата: 10.01.09 22:18
Оценка:
Здравствуйте, Mr.Cat, Вы писали:

N>>Пишу небольшую ВМ предусматриваю возможность вызова внешних (по отношению к коду ВМ) функций (пока что только для stdcall).


MC>Почему бы не хранить в байткоде VM все данные в network byte order и преобразовывать с помощью ntoh/hton в нативный порядок?


Это приведет к очень заметной потере эффективности, потому что такое преобразование придется делать перед и после каждой арифметической операции
Re[5]: Определить l/r endian в runtime
От: Mr.Cat  
Дата: 10.01.09 23:02
Оценка:
Здравствуйте, Pzz, Вы писали:
Pzz>Это приведет к очень заметной потере эффективности, потому что такое преобразование придется делать перед и после каждой арифметической операции

Network order можно использовать только для хранения констант в самом байткоде. А в рантайме в памяти все хранить в нативном порядке.

Либо я не понимаю, в чем проблема у автора топика.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.