Конференция "Прочее" » Вопрос про ASM команду sub
 
  • KSergey © (04.02.16 13:54) [0]
    Я понимаю, что, вероятно, надо идти читать документацию.
    но честное слово это момент не могу найти ответа, а где взять толковый краткий мануал (как было в мою бытность с Z80) - не ведаю, да и условные обозначения в доках, оказывается, уже не очень понимаю, а расшифровка не по глазам.

    Это были извинения за то, что такой вопрос задаю. Вопрос:

    Есть дизассемблированный код, в нём:
    len - integer
    pNonSpace, pStart - указатели pChar

    > pas:  len := pNonSpace - pStart + 1;
    mov  ecx, edi
    sub  exc,[ebp-$0c]
    jno здесь адрес перехода на "add  ecx, 01"
    call @IntOver
    add  ecx, 01
    .......



    Ну и далее там что-то, не важно.
  • KSergey © (04.02.16 13:58) [1]
    Собственно вопрос:
    Какие должны быть операнды  в
       sub  exc,[ebp-$0c]
    чтобы после неё взвёлся флаг OF ?

    Я думал, что оба операнда, например, должны быть больше MaxInt, но почему-то нет.
    Или exc (оно же pNonSpace) должно быть больше MaxInt, а вычитаемое (т.е. pStart) должно быть меньше MaxInt?

    (ну я предполагаю, что указатели - эти беззнаковый величины же и поэтому могут быть больше, чем знаковый Int)
  • KSergey © (04.02.16 14:43) [2]
    В общем спросил от отчаяния, пока писал пост - придумал как построить эксперимент, чтобы адреса в функцию передавались какие надо и проблему воспроизвёл.
    Как-нибудь напишу в чем было дело, глюк неожиданный и неприятный.

    По моему вопросу: нужен вариант номер 2, т.е. чтобы pNonSpace было более MaxInt, а pStart - менее MaxInt
  • Rouse_ © (04.02.16 14:45) [3]
    ну к примеру в ECX $80000000 а в памяти по адресу [EBP - $C] значение $7FFFFFFF
  • KSergey © (04.02.16 15:22) [4]
    Я, признаться, никак не могу сообразить логику выставления этого флага.
    Ну разве что он применим (осмысленен) сугубо для signed int типов, а для unsigned int смысла не имеет?
  • KSergey © (04.02.16 15:24) [5]
    ( друзья, я в общем-то в теме и осознаю, что для процессора нет разницы между signed и unsigned типами, и что это лишь вопрос трактовки; но именно трактовку и "бизнес смысл" и пытаюсь понять)
  • Inovet © (04.02.16 15:50) [6]
    123-124 не выставляется?
  • Rouse_ © (04.02.16 15:52) [7]

    > Ну разве что он применим (осмысленен) сугубо для signed
    > int типов, а для unsigned int смысла не имеет?

    Процессор не знает о том что за число (SIGNED/UNSIGNED) поэтому это возлагается на компилятор, который генерирует различные инструкции условного перехода при работе с такими типами.

    К примеру

    var
     A, B: DWORD;
    ...
       if A < B then


    Здесь будет использоваться инструкция JBE в которой задействованы флаги CF и ZF, а вот для такого случая:

    var
     A, B: Integer;
    ...
       if A < B then


    Будет использоваться инструкция JLE где прыжок осуществляется уже по совокупности флагов ZF, SZ и OF

    А флаги будут выставляться всегда.
  • Rouse_ © (04.02.16 15:55) [8]

    > Inovet ©   (04.02.16 15:50) [6]
    > 123-124 не выставляется?

    нет конечно
  • Rouse_ © (04.02.16 15:57) [9]
    Если есть желание разобраться по какому принципу выставляются флаги - то вот пример (сори на сях - но там все очень просто): http://rouse.drkb.ru/tmp/cmp.zip
  • Rouse_ © (04.02.16 16:01) [10]
    ЗЫ: в vmCMP8() происходит вычитание второго числа из первого - как раз искомый SUB
  • Inovet © (04.02.16 16:07) [11]
    > [8] Rouse_ ©   (04.02.16 15:55)

    Полез проверять.

    mov eax, 124
    sub eax, 1   ; Сбросился
    mov eax, 124
    sub eax, ecx ; Выставился. Уф.

  • Rouse_ © (04.02.16 16:13) [12]

    > Inovet ©   (04.02.16 16:07) [11]

    Ты точно про OF флаг говоришь?
    Этот код не выставляет OF флаг.
  • Inovet © (04.02.16 16:18) [13]
    > [12] Rouse_ ©   (04.02.16 16:13)
    > Ты точно про OF флаг говоришь?

    Блин, а я ж про CF думал.:)
  • KSergey © (04.02.16 16:20) [14]
    А всё же, логика выставления OF флага?
  • Rouse_ © (04.02.16 16:21) [15]

    > Inovet ©   (04.02.16 16:18) [13]
    > > [12] Rouse_ ©   (04.02.16 16:13)
    > > Ты точно про OF флаг говоришь?
    >
    > Блин, а я ж про CF думал.:)

    Угу я даж ролик успел снять, подумал мошт у меня крыша поехала :)
    http://rouse.drkb.ru/tmp/1.mp4
  • Rouse_ © (04.02.16 16:26) [16]

    > KSergey ©   (04.02.16 16:20) [14]
    > А всё же, логика выставления OF флага?

    так она простая:

    if (!aBit && bBit && flags.SF)
     flags.OF = true;
    if (aBit && !bBit && !flags.SF)
     flags.OF = true;



    т.е. смотрим старшие биты у обоих чисел (это SIGN бит и смотрим SF флаг, который выставляется от операции сложения первого и инвертированного второго числа).

    Грубо говоря этим мы проверяем - происходил ли переход через $80000000 (перенос бита в более старший разряд)
  • Inovet © (04.02.16 16:36) [17]
    > [16] Rouse_ ©   (04.02.16 16:26)
    > так она простая

    Для интереса в Вики посмотрел - есть там!
    https://ru.wikipedia.org/wiki/%D0%A4%D0%BB%D0%B0%D0%B3_%D0%BF%D0%B5%D1%80%D0%B5%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F
  • Rouse_ © (04.02.16 16:36) [18]
    Давай попробую по другому, вот смотри пример от Inovet
    От числа 123 отнимает 124.
    Отнимать будем через сложение, т.е. выразим как оба этих числа (в 16 ричной) как
    7B (123)
    и FFFFFF84 (минус 124)

    сложим их - получим результат = $FFFFFFFF т.е. число минус 1 - которое полностью укладывается в диапазон 32 бит.

    Теперь берем пой пример:
    первое число $80000000
    второе $7FFFFFFF

    второе инвертируем: оно становится равно $80000001

    складываем - на выходе число: $100000001 - а вот оно уже в 32 бита не влезет, самый старшая единичка находится в 33-ем бите - оть это и есть переполнение.

    Так понятно?
  • Pavia © (04.02.16 16:43) [19]

    > А всё же, логика выставления OF флага?

    Флаг OF взводится если результат не влазит в размеры операнда. Операнд для этого флага трактуется как знаковый.
    SInt8 = от -128 до 127
    К примеру
    SUB (-128), 1
    Результат -129 не влазит в SInt8 следовательно возводится OF.
    SUB 1, -127
    Результат 128 не влазит в SInt8 следовательно возводится OF.


    function SUB8(a,b:UInt8):UInt16;
    begin
    Result:=a-b;
    _ZF:=Ord(Result=0);
    _SF:=(Result  shr 7)  and 1;
    _PF:=PF_Table[Result and $FF];
    _OF:= (((a xor b) and (a xor result)) shr 7)and 1;
    _CF:=(Result  shr 8) and 1;

    _AF:=((a xor b xor result) shr 4) and 1;
    end;
  • Rouse_ © (04.02.16 16:50) [20]

    > Pavia ©   (04.02.16 16:43) [19]

    Что за PF_Table, покажи плз
  • Rouse_ © (04.02.16 17:00) [21]
    А все - не надо, собственно сам по быстрому построил :)
  • Pavia © (04.02.16 17:00) [22]
    Я уже не помню что там к чему.

    for i:=0 to 255 do
    PF_Table[i]:=1 and (1 xor i xor (i shr 1) xor (i shr 2) xor (i shr 3)
                   xor (i shr 4) xor (i shr 5) xor (i shr 6) xor (i shr 7));
  • Rouse_ © (04.02.16 17:04) [23]
    Parity флаг - четное кол-во включенных бит в младшем байте (True/False).
  • KSergey © (04.02.16 18:04) [24]
    > Rouse_ ©   (04.02.16 16:36) [18]

    Да, мне всё понятно. Спасибо.

    > Pavia ©   (04.02.16 16:43) [19]

    И вам тоже спасибо!
  • Rouse_ © (04.02.16 18:06) [25]
    Обращайся :)
  • Rouse_ © (04.02.16 18:14) [26]
    Да и кстати, по поводу мануалов: http://www.intel.ru/content/www/ru/ru/processors/architectures-software-developer-manuals.html

    их лучше периодически перезакачивать, бо обновляются иногда.
  • KSergey © (07.04.16 15:42) [27]
    Как-то я не отписался о сути. Проблема разобрана, хоть от этого и не легче.

    Оказалась совершенно неожиданная мерзопакость в D5 в том, что вот в таком коде

       len: Integer;
       pStart, pNonSpace: PChar;
    .....
       len := pNonSpace - pStart + 1;


    при включенной опции компилятора "Check inneger overflow" компилятор после выражения pNonSpace - pStart впендюривает проверку на переполнение Int'а.
    Причем не зависимо от типа переменной len: хоть Integer, хоть Cardinal. И даже если +1 убрать.

    И как только получается так, что pNonSpace указывает на адрес за границей 2 Гб, а  pStart указывает на адрес до 2 Гб (при этом разница может быть и совсем небольшой) - получаем EIntegerOverflow на этой строке.

    Кто догадался такую проверку вставить для указателей - не знаю.
  • Rouse_ © (07.04.16 16:21) [28]
    А так?
    len := Integer(pNonSpace - pStart + 1);
  • Rouse_ © (07.04.16 16:29) [29]
    Не, соврал:

    var
      len: DWORD;
      pStart, pNonSpace: PAnsiChar;
    begin
     try
       pStart := Pointer($7FFFFFFF);
       pNonSpace := pStart + $FFFFFF;
      len := DWORD(pNonSpace) - DWORD(pStart) + 1;
  • Rouse_ © (07.04.16 16:36) [30]
    Вот а логика простая, это можно увидеть из асм кода - изначально PChar кастится к Integer (так всегда было), стало быть использует при проверке OF флаг в частности генерацией JNO инструкции.
    Нужно всего лишь объяснить компилеру что у нас тут переполнения по SIGN-биту нет, сделав каст любому устраивающему нас UNSIGNED типу (DWORD/Cardinal/ULong и т.п.)

    В этом случае компилер сгенерирует JNB инструкцию, и все решиться нормально.
  • KSergey © (07.04.16 19:29) [31]
    > Rouse_ ©   (07.04.16 16:36) [30]
    > сделав каст любому устраивающему нас UNSIGNED типу (DWORD/Cardinal/ULong и т.п.)

    Это да.
    Но скажите мне: кто в борланде решил, что поинтер в Win32 - знаковый?!
    Я понимаю, что в ту пору (примерно Windows 95, я думаю) про достижение 2Гб памяти и подумать никто не мог (к вопросу о странном развитии техники), но всё же теория-то была изложена, а теория - она про 4Гб (и 32-х битные указатели) сразу была!

    Ну и потом: в своём коде я, конечно, могу переписать, но есть и "не мой" код, весь не перепроверишь.

    Интересно, в текущих версиях дельфи - так же?
  • Rouse_ © (07.04.16 19:37) [32]
    Ну смотри в 32 битых ты оперируешь памятью до 7fffffff - вылезешь за нее будет больно.
    Логично? Да еще как
  • KSergey © (07.04.16 19:47) [33]
    > Rouse_ ©   (07.04.16 19:37) [32]
    > Ну смотри в 32 битых ты оперируешь памятью до 7fffffff

    Это почему?! почему на ваш взгляд  8-й проводок в старшем байте не может принять состояние логической единицы? чем он такой особенный?
    я не понимаю.
  • Inovet © (07.04.16 20:46) [34]
    > [33] KSergey ©   (07.04.16 19:47)
    > Это почему?! почему на ваш взгляд  8-й проводок в старшем
    > байте не может принять состояние логической единицы?

    В Майкрософт тоже когда-то сложился знаковый тип? Ну как бы - вот вам половина, а остальное не трожьте.:)
  • Pavia © (07.04.16 21:09) [35]
    Для win 95-98 это ещё имело смысл. А вот в других ОС нет никакого смысла.
  • Игорь Шевченко © (07.04.16 21:24) [36]

    > Ну смотри в 32 битых ты оперируешь памятью до 7fffffff -
    >  вылезешь за нее будет больно.


    Не всегда
  • Rouse_ © (08.04.16 00:38) [37]
    Ну просто потому что изначальная адресация виртуальной памяти 32 битного приложения была ограничена именно этим числом.
    Впрочем Игорь правильно меня поправил - можно расширить диапазон адресации, но как это обьяснить компилеру?
  • Германн © (08.04.16 01:30) [38]

    > Rouse_ ©   (07.04.16 16:36) [30]
    >
    > Вот а логика простая, это можно увидеть из асм кода - изначально
    > PChar кастится к Integer (так всегда было)

    Ну вот а нафига так всегда было? :)
  • Rouse_ © (08.04.16 02:02) [39]
    Сереж, я ж уже объяснил, блин (че как дети прям, книжки не читаете) - 4 гига виртульной памяти дели на лапопам, первая твоя, вторая ядра.
  • Pavia © (08.04.16 06:31) [40]

    > Сереж, я ж уже объяснил, блин (че как дети прям, книжки
    > не читаете) - 4 гига виртульной памяти дели на лапопам,
    > первая твоя, вторая ядра.

    Так у вас логика не правильная. Ядро отображалось в адресный процесс приложения для того что-бы приложение могло адресовать к ядру. Иначе нет смысла. К примеру чтение значение таймера. Поэтому ваша логика не верна.
  • KSergey © (08.04.16 08:16) [41]
    > Rouse_ ©   (08.04.16 00:38) [37]
    > Впрочем Игорь правильно меня поправил - можно расширить
    > диапазон адресации, но как это обьяснить компилеру?

    А не надо ему объяснять, адресация - она все 4 Гб памяти должна быть, по-моему. Ну раз ОС мне физически даёт туда доступ - почему компилятор это ограничивает? ("кто он вообще такой?!")

    Впрочем, вы уже пояснили, похоже, логика разработчиков такая и была.
  • Pavia © (08.04.16 08:50) [42]

    > доступ - почему компилятор это ограничивает? ("кто он вообще
    > такой?!")

    D2 первый 32 битный компилятор создавался на Win98.
    В Win98 все лазили выше 2Гб и поэтому она постоянно висла. небыло защиты от записи.
    Если бы разработчики D2 не заприметили это то отладка стала бы кошмаром.
  • Pavia © (08.04.16 08:54) [43]
    *заприметили -> запретили
  • Rouse_ © (08.04.16 10:01) [44]

    > Pavia ©   (08.04.16 06:31) [40]
    > Так у вас логика не правильная. Ядро отображалось в адресный
    > процесс приложения для того что-бы приложение могло адресовать
    > к ядру. Иначе нет смысла. К примеру чтение значение таймера.

    Та шо ты такое говоришь, отображение значения таймера ядром в процесс идет по фиксированному адресу в виде структуры KE_USER_SHARED_DATA.
    Показываю.
    http://rouse.drkb.ru/tmp/1.gif
  • Rouse_ © (08.04.16 10:04) [45]

    > KSergey ©   (08.04.16 08:16) [41]
    > А не надо ему объяснять, адресация - она все 4 Гб памяти
    > должна быть, по-моему. Ну раз ОС мне физически даёт туда
    > доступ - почему компилятор это ограничивает? ("кто он вообще
    > такой?!")

    Туда будет доступ если приложение собранного с использованием флага IMAGE_FILE_LARGE_ADDRESS_AWARE, указанного в FILE_HEADER.
    По умолчанию данный флаг отключен и лимит для 32 бит именно $7FFFFFFF
  • KSergey © (08.04.16 10:22) [46]
    Rouse, отстаиваемая вами позиция понятна, но мир уже как бэ изменился и очень сильно.
    Я ведь на с потолка придумал проблему, она в жизни имеет место быть, к сожалению. (Менеджер памяти подменён, да)
  • Игорь Шевченко © (08.04.16 10:24) [47]
    Pavia ©   (08.04.16 08:50) [42]


    > D2 первый 32 битный компилятор создавался на Win98.
    > В Win98 все лазили выше 2Гб и поэтому она постоянно висла.
    >  небыло защиты от записи.


    Это какой-то феерический трындец.

    У меня к тебе огромная просьба - не пиши пожалуйста на форум, не оскорбляй мои религиозные чувства.
  • Rouse_ © (08.04.16 10:27) [48]

    > KSergey ©   (08.04.16 10:22) [46]
    > Rouse, отстаиваемая вами позиция понятна, но мир уже как
    > бэ изменился и очень сильно.

    Это не позиция - это знания, подкрепленные как аргументами, так и фактами :)
  • NoUser © (08.04.16 17:47) [49]
    KSergey,
    > почему компилятор это ограничивает?
    сами просили "Check integer overflow" !

    > но мир уже как бэ изменился и очень сильно.
    ого, а проблема где проявилась:
    на x32, x32+3G, x64 ?
  • Pavia © (08.04.16 20:18) [50]

    > Та шо ты такое говоришь, отображение значения таймера ядром
    > в процесс идет по фиксированному адресу в виде структуры
    > KE_USER_SHARED_DATA.Показываю.

    Так я говорю про то что было в 98 году. И то что сейчас оно совершенно по другому. И уже не требуется приложениям лазить в ядро.
  • Rouse_ © (09.04.16 00:26) [51]
    Открою великую тайну - приложение даже в 95-98 годах в ядро не лезло, ну это так, для общего понимания
  • Германн © (09.04.16 01:03) [52]

    > Rouse_ ©   (08.04.16 02:02) [39]
    >
    > Сереж, я ж уже объяснил, блин (че как дети прям, книжки
    > не читаете)

    Сань, какие именно глупые книжки нужно читать?  :)
    При чём тут "лампомпам" и приведение указателя к знаковому целому?
    <OFFTOP>
    Вот уже второй раз за последнее время ты мне "объясняешь" логику компилятора, а я эту логику  второй раз никак понять не могу. :(
    </OFFTOP>
  • Rouse_ © (09.04.16 01:36) [53]
    Сдаюсь, на днюхе персонально тебе на бумашке нарисую :)
  • Германн © (09.04.16 02:45) [54]

    > Rouse_ ©   (09.04.16 01:36) [53]
    >
    > Сдаюсь, на днюхе персонально тебе на бумашке нарисую :)
    >  

    Сомневаюсь я однако, что "на днюхе" найдётся для этого время. :)
  • Inovet © (09.04.16 02:50) [55]
    > [50] Pavia ©   (08.04.16 20:18)
    > И уже не требуется приложениям лазить в ядро.

    Одно удовольствие читать твои посты:) - так (я) и курить (табак) бросить. Пиши исчё.
  • Игорь Шевченко © (10.04.16 10:37) [56]

    > Но скажите мне: кто в борланде решил, что поинтер в Win32
    > - знаковый?!


    http://docwiki.embarcadero.com/RADStudio/XE8/en/Pointers_and_Pointer_Types_(Delphi)

    Указатель беззнаковый тип (что вобщем-то разумно). Но с указателями недопустимы арифметические операции (если справку почитать). А если ты все-таки выполняешь эти операции, то компилятор приводит их к типу Integer, что тоже разумно.

    Ни с какой адресацией памяти это не связано, просто совпадение.
  • KSergey © (10.04.16 15:02) [57]
    > Игорь Шевченко ©   (10.04.16 10:37) [56]
    > Но с указателями недопустимы арифметические операции (если справку  почитать)

    Да они издеваются!
  • Eraser © (10.04.16 15:24) [58]
    в дополнение к [56] надо отметить, что для работы с указателями, как с целыми числами лучше использовать тип UIntPtr/IntPtr ну или NativeUInt, иначе могут возникнуть проблемы на 64 битных версиях программы.
  • Mystic © (11.04.16 15:29) [59]
    Я так и не понял, был ли дан ответ: The SUB instruction performs integer subtraction. It evaluates the result for both signed and unsigned integer operands and sets the OF and CF flags to indicate an overflow in the signed or unsigned result, respectively. The SF flag indicates the sign of the signed result.

    Проще говоря, OF показывает, было ли переполнение, если операнды рассматриваются как SIGNED. Например, для байта (-100) SUB (100) возникает переполение для SIGNED (-200 не помещается в байт). Для UNSIGNED переполнения нет (156) - (100) = 56, поэтому CF сброшен. Другой возможный случай, напримкр, когда (100) SUB (-100), тут тоже переполнение для SIGNED (200 не помещается в байт), и для UNSIGNED тоже (100) SUB (156) больше нуля.
  • Rouse_ © (11.04.16 16:26) [60]

    > Игорь Шевченко ©   (10.04.16 10:37) [56]
    > Указатель беззнаковый тип (что вобщем-то разумно). Но с
    > указателями недопустимы арифметические операции (если справку
    > почитать). А если ты все-таки выполняешь эти операции, то
    > компилятор приводит их к типу Integer, что тоже разумно.
    >  
    >
    > Ни с какой адресацией памяти это не связано, просто совпадение.
    >

    Хм, ну странно конечно, но я как раз в какой-то из статей именно про эту адресацию и арифметические операции и читал (дабы не уплыло все, как говорится).
    Попробую найти - не склероз же у меня.
  • Rouse_ © (11.04.16 16:28) [61]
    В противном случае нелогичность будет наблюдаться ибо матоперации сложения/вычитания/умножения могут производится и над незнаковыми числами и в этом случае нет смысла ограничивать их интом.
  • Inovet © (11.04.16 16:57) [62]
    > [61] Rouse_ ©   (11.04.16 16:28)
    > сложения/вычитания/умножения

    Не ну в Си, например, если я ничё не забыл, чётко определено сложение/вычитание с целым результат указатель, разность двух указателей результат целое, А умножение тут каким боком прикрутить?
  • Rouse_ © (11.04.16 18:49) [63]
    mov eax, [eax + edx * 4] к примеру
  • Inovet © (11.04.16 21:55) [64]
    > [63] Rouse_ ©   (11.04.16 18:49)
    > mov eax, [eax + edx * 4] к примеру

    Так здесь не указатель умножается, а индекс.
  • KSergey © (12.04.16 08:59) [65]
    Я, пожалуй, понял в чем были философские обоснования создателей.
    Пока речь идёт про вычитание меньшего адреса из большего - всё укладывается в беззнаковые типы.
    Но ведь программист может от меньшего указателя отнять больший. И даже, вероятно, ожидает получить отрицательное число, почему нет.
    Чтобы эти коллизии как-то обыграть - придумали простое правило: приводить к знаковым.

    Руки им за это оторвать.
  • Игорь Шевченко © (12.04.16 12:24) [66]
    KSergey ©   (12.04.16 08:59) [65]

    Never attribute to malice which can be adequately explained by stupidity.
  • KSergey © (12.04.16 13:41) [67]
    Спасибо, (погуглив) узнал много нового.
 
Конференция "Прочее" » Вопрос про ASM команду sub
Есть новые Нет новых   [134431   +15][b:0.001][p:0.002]