На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Запрещается обсуждать написание вирусов, троянов и других вредоносных программ!
2. Помните, что у нас есть FAQ раздела Assembler и Полезные ссылки. Посмотрите, возможно, там уже имеется решение вашего вопроса.

3. Настоятельно рекомендуем обратить особое внимание на правила форума, которые нарушаются чаще всего:
  3.1. Заголовок темы должен кратко отражать её суть. Темы с заголовками типа "Срочно помогите!" или "Ассемблер" будут отправляться в Корзину для мусора.
  3.2. Исходники программ обязательно выделяйте тегами [code]...[/code] (одиночные инструкции можно не выделять).
  3.3. Нежелательно поднимать старые темы (не обновлявшиеся более года) без веской на то причины.

Не забывайте также про главные Правила форума!

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
Страницы: (3) 1 [2] 3  все  ( Перейти к последнему сообщению )  
> floating-point invalid в dll
    Попробую сделать так:
    __asm {
    MOV EAX, 0x1332;
    PUSH EAX;
    FLDCW [ESP];
    POP EAX;
    }
    Сейчас нет возможности проверить, т.к. винда 64 бита.

    Добавлено
    Спасибо всем заранее.
      Цитата Abraziv @
      Попробую сделать так
      Попробуйте 0x133F, т.к. это замаскирует все ошибки, и исключения при ошибках вызываться не будут. Но вообще, если причина в этом, значит либо в коде DLL ошибка, либо ей передаются неверные данные, которые не проверяются.

      Цитата Abraziv @
      Не в 64 битном режиме, а на 64 битной винде 32 битное приложение.
      В 32-битных программах соглашений куча. И они могут быть другими в Borland'е (и Borland - это что: Builder, Delphi...?) А в какой винде запускается 32-битная прога (x86 или x64) разницы быть не должно. Если возникает ошибка только в x86, то это странно.

      Почему не хотите прислать DLL и код, который его вызывает (рабочий - борландовский и MSVSCP)? Мы бы могли посмотреть в отладчике что происходит, а не гадать на кофейной гуще.
      И что вообще эта функция должна делать?
      Может, там вообще глюк из разряда: нужно передать Double через 2 даблворда в стеке, а он передаётся через ссылку...

      p.s. CW - управляющее слово только, а не кодовое ;)

      Добавлено
      Только сейчас увидел сообщение в личке... :)
        Вангую переполнение стека FPU.
          В общем, ситуация следующая...
          DLL-функция вызывает функцию Trunc(X), которая удаляет дробную часть числа. Результат возвращается в виде 64-битного целого.
          Код этой функции таков:
          ExpandedWrap disabled
            add esp,FFFFFFF4
            wait
            fnstcw word ptr ss:[esp]
            wait
            mov al,byte ptr ss:[esp+1]
            or byte ptr ss:[esp+1],C
            fldcw word ptr ss:[esp]
            fistp qword ptr ss:[esp+4]
            mov byte ptr ss:[esp+1],al
            fldcw word ptr ss:[esp]
            mov eax,dword ptr ss:[esp+4]
            mov edx,dword ptr ss:[esp+8]
            add esp,C
            ret
          Т.е. читается CW, устанавливаются биты, отвечающие за округление в режим "обрезания дробной части", выполняется fistp, затем CW восстанавливается.

          Так вот, каждый раз туда передаётся число, вдвое больше предыдущего (с вычетом единицы). В определённый момент (на последнем цикле) значение этого числа выходит за рамки 64 битного знакового числа, fistp помечает соответствующие биты в SW (status word) о том, что произошла исключительная ситуация, однако исключения сразу не происходит (оно происходит при вызове fwait и т.п. инструкций, в т.ч. после fldcw). И тут попадается fldcw, и возникает исключение.
          Почему только в 32-битной Windows? Потому что в 64-битной Windows CW=027F, в 32-битной CW=1272 (по крайней мере, в 7-ке, все вопросы к мелкомягким и их VSC++). Т.е. в 32-битной не замаскировано исключение #IA (invalid arithmetic), которое возникает при записи слишком большого значения как целого.

          Что делать?
          Вызывать finit из основной проги перед вызовом функции armInit :)
          Или выполнять такой код:
          ExpandedWrap disabled
                short CW, CWnew;
                __asm {
                    fnstcw CW
                    fnstcw CWnew
                    or CWnew, 1  // можно сделать or CWnew,0x3F для надёжности :)
                    fldcw CWnew
                }
                amrInit(0);
                __asm fldcw CW


          Добавлено
          Ну или так:
          ExpandedWrap disabled
                __asm {
                    push eax
                    fnstcw [esp]
                    push eax
                    fnstcw [esp]
                    or [esp], 1
                    fldcw [esp]
                    pop eax
                }
                amrInit(0);
                __asm {
                    fldcw [esp]
                    pop eax
                }
            В таком случае это не проблема ОСи. Trunc() не должна сообщать о проблеме, т.к. от проебразования к unsigned __int64 требуется беззнаковый результат, значит коли это происходит, Trunc() реализована неверно.
              А это и не проблема оси. Это проблема MSVCPP, потому что на момент старта программы CW=027F как в 32 битах, так и в 64-х. И прога его меняет его ещё до вызова mainCRTStartup в зависимости от битности винды...
                Цитата Jin X @
                Это проблема MSVCPP, потому что на момент старта программы CW=027F как в 32 битах, так и в 64-х. И прога его меняет его ещё до вызова mainCRTStartup в зависимости от битности винды...
                Хм.
                Visual Studio 2015:
                Цитата _control87, _controlfp, __control87_2
                По умолчанию библиотеки времени выполнения маскируют все исключения для операций с плавающей запятой .
                И насколько я помню, так было всегда. Кто-то однозначно неправ.

                Добавлено
                Попробую ещё раз вангануть: dll имеет и другие проблемы, по крайней мере с совместимостью.
                Сообщение отредактировано: Qraizer -
                  Цитата Qraizer @
                  Попробую ещё раз вангануть: dll имеет и другие проблемы, по крайней мере с совместимостью.
                  Ну, скорее всего, да.
                  Пустой проект показывает нормальный CW (027F) к моменту mainCRTStartup...
                    Переписать код. Видишь ли, var = (unsigned __int64) (pow(2.0, (double) k) - 1.0); работает – если работает – по чистой случайности. FPU не имеет беззнаковых типов, даже целочисленных. При сохранении в квадрословное целое FPU всегда сохраняет его как знаковое. Если подать ему 263, то будет фиксироваться переполнение, о котором сообщается через IA. Если оно замаскировано, то маскированной реакцией является возврат целочисленной неопределённости, которая имеет вид минимально возможного (знакового) целого, т.е. 0x8000000000000000. И оно по чистой случайности совпадает с 263 в беззнаковом целом формате.
                      NaN – это нечисло. Думаю, этого достаточно, чтобы понять абсурдность желания. NaN появляется в вычислениях, которые невозможно вычислить. Они не имеют результата. Даже если поделить 123 на 0, будет не NaN, а всего лишь INF, с которым в принципе можно продолжать вычисления. При делении 0 на 0 будет NaN.
                      Если твоему алгоритму подходят выражения без результата, то мне сложно представить, что полезного такой алгоритм в состоянии предложить.
                        Цитата Qraizer @
                        Видишь ли, var = (unsigned __int64) (pow(2.0, (double) k) - 1.0); работает – если работает – по чистой случайности.
                        ... Если подать ему 263, то будет фиксироваться переполнение

                        С чего это? В соответствии с выражением к целому должно приводиться не 263, а 263-1.0 = _I64_MAX. Может просто ms-оптимизатор тупит, заменяя вещественное вычитание целочисленным?
                          leo, Qraizer, вы оба правы, только есть нюанс: точность.
                          Оптимизатор не тупит, всё нормально. В Trunc передаётся уже 263-1, но! Мантисса FPU (при 80-битной точности) содержит 63 бита (без знака). 263-1 – это ещё 63 бита, а вот 263 – уже 64. После pow результат содержит число 263, после него идёт вычитание единицы (fsub), вот только вычесть эту единицу он не может, т.к. точности не хватает, и там остаётся 263. И при преобразовании в unsigned __int64:
                          Цитата Qraizer @
                          оно по чистой случайности совпадает с 263 в беззнаковом целом формате
                          :)

                          Добавлено
                          Хотя результат по задумке должен быть 263-1... так что, уж не знаю в какой момент эта DLL-ка глюканёт при дальнейшей работе...

                          Добавлено
                          Вспоминается статья про Закон дырявых абстракций...
                          Как раз в тему... :)
                            Хотя, нет, немного не так... FPU нормально вычитает единицу из 263 при точности FPU-операций в 80 бит, результат же умещается в 63 бита. Проблема в другом: CW=1272 в 32 битах и CW=027F в 64 битах. А это вычисления с точностью double, т.е. 64 бита (где составляет 52 бита без учёта знака), т.е. результат будет неверным (без вычета единицы) значительно раньше, чем на последнем цикле. Так что, решить первоначальную проблему лучше изменением в CW не младшего бита, а установкой значения 3 в битах 8-9:
                            ExpandedWrap disabled
                                  __asm {
                                      push eax
                                      fnstcw [esp]
                                      or word ptr [esp],0x300  // если ошибки всё же будут возникать (уже в другом месте), можно заменить 0x300 на 0x301, но тогда будет потеря точности вычислений (местами весьма серьёзная)... но такого быть уже не должно
                                      fldcw [esp]
                                      pop eax
                                  }
                                  amrInit(0);

                            Тогда и результаты вычислений будут верными...
                              Спасибо за ответ. Огромное спасибо. Сейчас буду тестировать. После отпишусь. Скажу сразу же, прога не падает после асм вставки.
                                Цитата Jin X @
                                Мантисса FPU (при 80-битной точности) содержит 63 бита (без знака)...

                                Учти, что вычисляется степень двойки, а двоичная мантисса любого числа 2N строго равна 1 и представляется абсолютно точно в любом вещественном формате. Не знаю, как в билдере и мсвс, а в дельфях math.Power(..) для целых степеней считается через IntPower методом умножения, поэтому число 263 должно вычисляться абсолютно точно с мантиссой строго равной 1 без всякого дребезга в младших разрядах.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) 1 [2] 3  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0794 ]   [ 16 queries used ]   [ Generated: 28.03.24, 08:43 GMT ]