Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 2017.04.09;
Скачать: [xml.tar.bz2];

Вниз

Вопрос про ASM команду sub   Найти похожие ветки 

 
KSergey ©   (2016-02-04 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 ©   (2016-02-04 13:58) [1]

Собственно вопрос:
Какие должны быть операнды  в
   sub  exc,[ebp-$0c]
чтобы после неё взвёлся флаг OF ?

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

(ну я предполагаю, что указатели - эти беззнаковый величины же и поэтому могут быть больше, чем знаковый Int)


 
KSergey ©   (2016-02-04 14:43) [2]

В общем спросил от отчаяния, пока писал пост - придумал как построить эксперимент, чтобы адреса в функцию передавались какие надо и проблему воспроизвёл.
Как-нибудь напишу в чем было дело, глюк неожиданный и неприятный.

По моему вопросу: нужен вариант номер 2, т.е. чтобы pNonSpace было более MaxInt, а pStart - менее MaxInt


 
Rouse_ ©   (2016-02-04 14:45) [3]

ну к примеру в ECX $80000000 а в памяти по адресу [EBP - $C] значение $7FFFFFFF


 
KSergey ©   (2016-02-04 15:22) [4]

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


 
KSergey ©   (2016-02-04 15:24) [5]

( друзья, я в общем-то в теме и осознаю, что для процессора нет разницы между signed и unsigned типами, и что это лишь вопрос трактовки; но именно трактовку и "бизнес смысл" и пытаюсь понять)


 
Inovet ©   (2016-02-04 15:50) [6]

123-124 не выставляется?


 
Rouse_ ©   (2016-02-04 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_ ©   (2016-02-04 15:55) [8]


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

нет конечно


 
Rouse_ ©   (2016-02-04 15:57) [9]

Если есть желание разобраться по какому принципу выставляются флаги - то вот пример (сори на сях - но там все очень просто): http://rouse.drkb.ru/tmp/cmp.zip


 
Rouse_ ©   (2016-02-04 16:01) [10]

ЗЫ: в vmCMP8() происходит вычитание второго числа из первого - как раз искомый SUB


 
Inovet ©   (2016-02-04 16:07) [11]

> [8] Rouse_ ©   (04.02.16 15:55)

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

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


 
Rouse_ ©   (2016-02-04 16:13) [12]


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

Ты точно про OF флаг говоришь?
Этот код не выставляет OF флаг.


 
Inovet ©   (2016-02-04 16:18) [13]

> [12] Rouse_ ©   (04.02.16 16:13)
> Ты точно про OF флаг говоришь?

Блин, а я ж про CF думал.:)


 
KSergey ©   (2016-02-04 16:20) [14]

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


 
Rouse_ ©   (2016-02-04 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_ ©   (2016-02-04 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 ©   (2016-02-04 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_ ©   (2016-02-04 16:36) [18]

Давай попробую по другому, вот смотри пример от Inovet
От числа 123 отнимает 124.
Отнимать будем через сложение, т.е. выразим как оба этих числа (в 16 ричной) как
7B (123)
и FFFFFF84 (минус 124)

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

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

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

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

Так понятно?


 
Pavia ©   (2016-02-04 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_ ©   (2016-02-04 16:50) [20]


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

Что за PF_Table, покажи плз


 
Rouse_ ©   (2016-02-04 17:00) [21]

А все - не надо, собственно сам по быстрому построил :)


 
Pavia ©   (2016-02-04 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_ ©   (2016-02-04 17:04) [23]

Parity флаг - четное кол-во включенных бит в младшем байте (True/False).


 
KSergey ©   (2016-02-04 18:04) [24]

> Rouse_ ©   (04.02.16 16:36) [18]

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

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

И вам тоже спасибо!


 
Rouse_ ©   (2016-02-04 18:06) [25]

Обращайся :)


 
Rouse_ ©   (2016-02-04 18:14) [26]

Да и кстати, по поводу мануалов: http://www.intel.ru/content/www/ru/ru/processors/architectures-software-developer-manuals.html

их лучше периодически перезакачивать, бо обновляются иногда.


 
KSergey ©   (2016-04-07 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_ ©   (2016-04-07 16:21) [28]

А так?
len := Integer(pNonSpace - pStart + 1);


 
Rouse_ ©   (2016-04-07 16:29) [29]

Не, соврал:

var
  len: DWORD;
  pStart, pNonSpace: PAnsiChar;
begin
 try
   pStart := Pointer($7FFFFFFF);
   pNonSpace := pStart + $FFFFFF;
  len := DWORD(pNonSpace) - DWORD(pStart) + 1;


 
Rouse_ ©   (2016-04-07 16:36) [30]

Вот а логика простая, это можно увидеть из асм кода - изначально PChar кастится к Integer (так всегда было), стало быть использует при проверке OF флаг в частности генерацией JNO инструкции.
Нужно всего лишь объяснить компилеру что у нас тут переполнения по SIGN-биту нет, сделав каст любому устраивающему нас UNSIGNED типу (DWORD/Cardinal/ULong и т.п.)

В этом случае компилер сгенерирует JNB инструкцию, и все решиться нормально.


 
KSergey ©   (2016-04-07 19:29) [31]

> Rouse_ ©   (07.04.16 16:36) [30]
> сделав каст любому устраивающему нас UNSIGNED типу (DWORD/Cardinal/ULong и т.п.)

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

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

Интересно, в текущих версиях дельфи - так же?


 
Rouse_ ©   (2016-04-07 19:37) [32]

Ну смотри в 32 битых ты оперируешь памятью до 7fffffff - вылезешь за нее будет больно.
Логично? Да еще как


 
KSergey ©   (2016-04-07 19:47) [33]

> Rouse_ ©   (07.04.16 19:37) [32]
> Ну смотри в 32 битых ты оперируешь памятью до 7fffffff

Это почему?! почему на ваш взгляд  8-й проводок в старшем байте не может принять состояние логической единицы? чем он такой особенный?
я не понимаю.


 
Inovet ©   (2016-04-07 20:46) [34]

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

В Майкрософт тоже когда-то сложился знаковый тип? Ну как бы - вот вам половина, а остальное не трожьте.:)


 
Pavia ©   (2016-04-07 21:09) [35]

Для win 95-98 это ещё имело смысл. А вот в других ОС нет никакого смысла.


 
Игорь Шевченко ©   (2016-04-07 21:24) [36]


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


Не всегда


 
Rouse_ ©   (2016-04-08 00:38) [37]

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


 
Германн ©   (2016-04-08 01:30) [38]


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

Ну вот а нафига так всегда было? :)


 
Rouse_ ©   (2016-04-08 02:02) [39]

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


 
Pavia ©   (2016-04-08 06:31) [40]


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

Так у вас логика не правильная. Ядро отображалось в адресный процесс приложения для того что-бы приложение могло адресовать к ядру. Иначе нет смысла. К примеру чтение значение таймера. Поэтому ваша логика не верна.


 
KSergey ©   (2016-04-08 08:16) [41]

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

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

Впрочем, вы уже пояснили, похоже, логика разработчиков такая и была.


 
Pavia ©   (2016-04-08 08:50) [42]


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

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


 
Pavia ©   (2016-04-08 08:54) [43]

*заприметили -> запретили


 
Rouse_ ©   (2016-04-08 10:01) [44]


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

Та шо ты такое говоришь, отображение значения таймера ядром в процесс идет по фиксированному адресу в виде структуры KE_USER_SHARED_DATA.
Показываю.
http://rouse.drkb.ru/tmp/1.gif


 
Rouse_ ©   (2016-04-08 10:04) [45]


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

Туда будет доступ если приложение собранного с использованием флага IMAGE_FILE_LARGE_ADDRESS_AWARE, указанного в FILE_HEADER.
По умолчанию данный флаг отключен и лимит для 32 бит именно $7FFFFFFF


 
KSergey ©   (2016-04-08 10:22) [46]

Rouse, отстаиваемая вами позиция понятна, но мир уже как бэ изменился и очень сильно.
Я ведь на с потолка придумал проблему, она в жизни имеет место быть, к сожалению. (Менеджер памяти подменён, да)


 
Игорь Шевченко ©   (2016-04-08 10:24) [47]

Pavia ©   (08.04.16 08:50) [42]


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


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

У меня к тебе огромная просьба - не пиши пожалуйста на форум, не оскорбляй мои религиозные чувства.


 
Rouse_ ©   (2016-04-08 10:27) [48]


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

Это не позиция - это знания, подкрепленные как аргументами, так и фактами :)


 
NoUser ©   (2016-04-08 17:47) [49]

KSergey,
> почему компилятор это ограничивает?
сами просили "Check integer overflow" !

> но мир уже как бэ изменился и очень сильно.
ого, а проблема где проявилась:
на x32, x32+3G, x64 ?


 
Pavia ©   (2016-04-08 20:18) [50]


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

Так я говорю про то что было в 98 году. И то что сейчас оно совершенно по другому. И уже не требуется приложениям лазить в ядро.


 
Rouse_ ©   (2016-04-09 00:26) [51]

Открою великую тайну - приложение даже в 95-98 годах в ядро не лезло, ну это так, для общего понимания


 
Германн ©   (2016-04-09 01:03) [52]

Удалено модератором


 
Rouse_ ©   (2016-04-09 01:36) [53]

Удалено модератором


 
Германн ©   (2016-04-09 02:45) [54]

Удалено модератором


 
Inovet ©   (2016-04-09 02:50) [55]

> [50] Pavia ©   (08.04.16 20:18)
> И уже не требуется приложениям лазить в ядро.

Одно удовольствие читать твои посты:) - так (я) и курить (табак) бросить. Пиши исчё.


 
Игорь Шевченко ©   (2016-04-10 10:37) [56]


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


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

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

Ни с какой адресацией памяти это не связано, просто совпадение.


 
KSergey ©   (2016-04-10 15:02) [57]

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

Да они издеваются!


 
Eraser ©   (2016-04-10 15:24) [58]

в дополнение к [56] надо отметить, что для работы с указателями, как с целыми числами лучше использовать тип UIntPtr/IntPtr ну или NativeUInt, иначе могут возникнуть проблемы на 64 битных версиях программы.


 
Mystic ©   (2016-04-11 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_ ©   (2016-04-11 16:26) [60]


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

Хм, ну странно конечно, но я как раз в какой-то из статей именно про эту адресацию и арифметические операции и читал (дабы не уплыло все, как говорится).
Попробую найти - не склероз же у меня.


 
Rouse_ ©   (2016-04-11 16:28) [61]

В противном случае нелогичность будет наблюдаться ибо матоперации сложения/вычитания/умножения могут производится и над незнаковыми числами и в этом случае нет смысла ограничивать их интом.


 
Inovet ©   (2016-04-11 16:57) [62]

> [61] Rouse_ ©   (11.04.16 16:28)
> сложения/вычитания/умножения

Не ну в Си, например, если я ничё не забыл, чётко определено сложение/вычитание с целым результат указатель, разность двух указателей результат целое, А умножение тут каким боком прикрутить?


 
Rouse_ ©   (2016-04-11 18:49) [63]

mov eax, [eax + edx * 4] к примеру


 
Inovet ©   (2016-04-11 21:55) [64]

> [63] Rouse_ ©   (11.04.16 18:49)
> mov eax, [eax + edx * 4] к примеру

Так здесь не указатель умножается, а индекс.


 
KSergey ©   (2016-04-12 08:59) [65]

Я, пожалуй, понял в чем были философские обоснования создателей.
Пока речь идёт про вычитание меньшего адреса из большего - всё укладывается в беззнаковые типы.
Но ведь программист может от меньшего указателя отнять больший. И даже, вероятно, ожидает получить отрицательное число, почему нет.
Чтобы эти коллизии как-то обыграть - придумали простое правило: приводить к знаковым.

Руки им за это оторвать.


 
Игорь Шевченко ©   (2016-04-12 12:24) [66]

KSergey ©   (12.04.16 08:59) [65]

Never attribute to malice which can be adequately explained by stupidity.


 
KSergey ©   (2016-04-12 13:41) [67]

Спасибо, (погуглив) узнал много нового.



Страницы: 1 2 вся ветка

Форум: "Прочее";
Текущий архив: 2017.04.09;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.63 MB
Время: 0.003 c
4-1282656910
Unknown_user
2010-08-24 17:35
2017.04.09
Запрет получения фокуса приложения


15-1454583291
KSergey
2016-02-04 13:54
2017.04.09
Вопрос про ASM команду sub


15-1459970604
K-1000
2016-04-06 22:23
2017.04.09
Кто играет в шахматы?


15-1460484629
Dmk
2016-04-12 21:10
2017.04.09
Регистрация Delphi


2-1439285376
Masterucs
2015-08-11 12:29
2017.04.09
Delphi XE: изменили FreeAndNil?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский