Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Прочие языки программирования > Assembler
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 17.11.2015, 21:24
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию E2171 Variable 'Pos' inaccessible here due to optimization

Привет форум!

Появилось желание некоторые функции в делфи переписать на ассемблере. Я не большой спец по ассемблеру, да собственно и не в нем вопрос. Есть такая вот функция, и сам код работает если взять асм блок в begin - end. Но в таком вот виде :

Код:
procedure TFGInt.Assign(aUnit: TFGInt; Pos: Word=0; Cnt: Word=0);
 label l1, l2;
//begin
    asm
     mov eax, [ebp-$04]  //положили в ebx  Self
     mov edi, [eax+$04]  //получилиSelf.fMemory
     add edi, $02        //сместились на Param
     mov ebx, [ebp-$08]  //положили в  ebx  aUnit
     mov esi, [ebx+$04]  //получили aUnit.fMemory
     add esi, $02        //сместились на Param
     movsw               //скопировали Param
     cmp Cnt, $00
     jne l1
     mov esi, [ebx+$04]   //получили aUnit.fMemory
     mov edx, [esi]        //если Cnt равен 0 то копируем в dx счетчик aUnit
     jmp l2
l1: mov dx, Cnt        //иначе положили в dx  Cnt
l2: call setCount      // в eax уже есть Self , в edx есть Cnt
     xor ecx, ecx
     mov cx, dx //установили счетчик цикла
     mov eax, [ebp-$04]  //положили в eax  Self
     mov edi, [eax+$4]   //получили Self.fMemory
     add edi, $04        //сместились на адрес начального блока Self
     mov ebx, [ebp-$08]  //положили в  ebx  aUnit
     mov esi, [ebx+$4]   //получили aUnit.fMemory
     mov eax, $04
     mul Pos
     add eax, $04
     add esi, eax //сместились на адрес начального блока aUnit
     rep movsd   //переписали блоки
   end;
//end

происходит ошибка.
я обнаружил что в параметре Pos передается мусор. В вотчлисте пишет: E2171 Variable 'Pos' inaccessible here due to optimization

какая оптимизация?? в проекте в CodeGeneration оптимизация выключена
наверное какаято глупая ошибка, но не соображу никак.
Ответить с цитированием
  #2  
Старый 17.11.2015, 22:32
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Откуда взяты конструкции вроде
Цитата:
mov eax, [ebp-$04] //положили в ebx Self
???
Особенно напрягает комментарий. При чем тут ebx?
К чему я. Во-первых, ebp делфи может (если хочет!) ставить в совершенно произвольное значение, и вовсе не обязательно там будет указатель стекового фрейма. Во-вторых, у делфи FastCall, и уж что-то, а Self наверняка передается через регистр (вероятнее всего ecx).
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 17.11.2015 в 22:37.
Ответить с цитированием
  #3  
Старый 18.11.2015, 00:03
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

конструкции эти создает сам компилятор
если поставить точку останова на начало
функции и посмотреть сасемблированный компилятором код
то можно увидеть

Код:
push ebp
move ebp,esp
add esp, -$0c
move [ebp-$02], cx
move [ebp-$08], eax
move [ebp-$0c], edx

потом идут строки моего кода

в eax приходит указатель на себя
в edx на aUnit
в ecx Cnt и Pos
причем как-то странно
например
pos=6 cnt=8 ecx $000E0006
pos=1 cnt=2 ecx $00030001
pos=7 cnt=9 ecx $00100007
тоесть в старшем слове ecx сумма pos+cnt
в младшем pos

это в варианте с блоком бегин энд

а если без то

Код:
push ebp
move ebp,esp
add esp, -$08
move [ebp-$04], eax
move [ebp-$08], edx



с комментарием. ну напутал чуть. сори

Последний раз редактировалось a.n.d.r.e.w, 19.11.2015 в 07:54.
Ответить с цитированием
  #4  
Старый 19.11.2015, 00:02
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

В коде нового поста используется ebp + X, в старом - ebp - X. В [ebp + 4] по идее вообще адрес возврата, а туда записывается eax?. Что-то с этим новым кодом не так.
Теперь, почему
Код:
mov edi, [eax+$04]  //получилиSelf.fMemory
? Я не вижу описания используемых классов. Может там и не 4. Вообще в делфи можно к полям обращаться из ассемблера, чтобы он сам посчитал смещения.
Цитата:
MOV EAX,(TRect PTR [EDX]).B.X
MOV EAX,TRect([EDX]).B.X
MOV EAX,TRect[EDX].B.X
MOV EAX,[EDX].TRect.B.X
Обращение по прямому смещению может обернуться плохими последствиями.
Третье. Ты говоришь, что
Цитата:
в ecx Cnt и Pos
В последнем приведенном коде ecx, содержащий Pos, не сохраняется. При этом в асм-коде он благополучно обнуляется и перезаписывается другим числом, а потом делается mul Pos. Это не может работать. Однако интересно, во что в таком случае вообще mul Pos транслируется.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 19.11.2015 в 00:16.
Ответить с цитированием
  #5  
Старый 19.11.2015, 12:03
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
В коде нового поста используется ebp + X, в старом - ebp - X. В [ebp + 4] по идее вообще адрес возврата, а туда записывается eax?. Что-то с этим новым кодом не так.

все верно эт я по памяти писал снова ошибся, говорю ж не специалист в асм )), конечно смещение отрицательное. исправил пост.

Попробую сначала.

Разрабатываю класс для работы с большими числами до нескольких сотен десятичных знаков. Такие используются в криптографии.
Хранится такое число кусками размером 4 байта, а методы класса оперируют этими кусками выполняя математические, логические, операции сравнения, копирования итд. по сути это массив.
но так как операции эти математические очень медленные на деле получаются, длинные циклы с длинными циклами, поэтому появилось желание оптимизировать базовые методы работы с массивом: доступ к элементами, изменение длины массива, копирование и.т.д.
раньше использовал простой массив Blocks: array of LongWord, Blocks[i], getLength(Blocks), setLength(Blocks) итд..
потом сделал через указатель меняю длину ReallocMem, блоки получаю смещаясь от базового указателя. Производительность выросла в несколько раз.
теперь решил пойти дальше обратиться к ассемблеру, заодно попрактиковаться. не помешает.

В общем в классе объявлена только один указатель fMemory
от него
по смещению 0 храню счетчик блоков 2байта
по смещению 2 храню параметры (знак числа, положение десятичной точки) тоже 2 байта
по смещению 4 первый блок

да в первом посте код кривой, не спорю, но работает
вопрос мой вот в чем:
внутри асм блока я хочу обращаться к передаваемой переменной Pos напрямую mul Pos , но так не всегда получается

вот так работает
Код:
procedure TFGInt.Assign(aUnit: TFGInt; Pos: Word=0; Cnt: Word=0);
 begin
  asm
   ....
    mul Pos
   ....
  end;
 end;

вот так нет
Код:
procedure TFGInt.Assign(aUnit: TFGInt; Pos: Word=0; Cnt: Word=0);
  asm
   ....
    mul Pos
   ....
  end;

во втором случае умножение eax происходит на произвольное число
а в вотчлисте E2171 Variable 'Pos' inaccessible here due to optimization

обойти проблему у меня в итоге получилось, разобрался
Pos передается в регистре cx и в первом и втором случае как оказалось в старшем слове ecx видимо вычисления предыдущей функции,
а счетчик передается в стеке по положительному смещению от esp, но со счетчиком нет проблем обращаясь явно к переменной Cnt

но все же что за фигня с оптимизацией?
подобная проблема начала появляться в других местах.
Ответить с цитированием
  #6  
Старый 19.11.2015, 19:50
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Я бы на твоем месте все же посмотрел, во что транслируется эта команда "mul Pos". Потому что Pos - как ты сам говоришь, в регистре, а регистр затирается.
Только вот еще одна вещь.
Цитата:
mov eax, $04
mul Pos
Есть команда SHL, которая не занимается медленным умножением, а сдвигает биты, что равносильно умножению на 2^x. При умножении на степень двойки (а число 4 - вторая степень двойки) SHL гораздо проще, быстрее и удобнее. Может и проблем меньше будет.

Что до оптимизации - не могу ничего сказать. Тут уже многое зависит от реализации самой делфы. Надо смотреть на сгенерированный ассемблерный код методов, чтобы понять, что не так. У меня, например, были случаи, когда VisualStudio при использовании встроенного ассемблера иногда не догадывалась сохранить регистры, или наоборот сохраняла их лишний раз и меняла тем самым все смещения от EBP. У делфи может быть то же самое в каких-то случаях.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 20.11.2015 в 00:24.
Ответить с цитированием
  #7  
Старый 20.11.2015, 15:06
Аватар для M.A.D.M.A.N.
M.A.D.M.A.N. M.A.D.M.A.N. вне форума
Sir Richard Abramson
 
Регистрация: 05.04.2008
Сообщения: 5,505
Версия Delphi: XE10
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Bargest
Откуда взяты конструкции вроде

???
Особенно напрягает комментарий. При чем тут ebx?
К чему я. Во-первых, ebp делфи может (если хочет!) ставить в совершенно произвольное значение, и вовсе не обязательно там будет указатель стекового фрейма. Во-вторых, у делфи FastCall, и уж что-то, а Self наверняка передается через регистр (вероятнее всего ecx).
fastcall
Код:
foo.ToString(1, 2)
eq
Код:
ToString(foo, 1, 2)
eax
__________________
— Как тебя понимать?
— Понимать меня не обязательно. Обязательно меня любить и кормить вовремя.


На Delphi, увы, больше не программирую.
Рекомендуемая литература по программированию
Ответить с цитированием
  #8  
Старый 20.11.2015, 15:35
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

M.A.D.M.A.N. не совсем понимаю какой вывод нужно сделать)
??

вот облегченный проект DelphiXE7
https://yadi.sk/d/9N2EbklKkbeQM

Последний раз редактировалось a.n.d.r.e.w, 20.11.2015 в 15:41.
Ответить с цитированием
  #9  
Старый 20.11.2015, 20:03
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

M.A.D.M.A.N., да, я знаю, что foo.tostring(1, 2) <=> TFoo_tostring(foo, 1, 2). Только не разбирался, через что передается Self в данном случае. Понимаю, что прямое следование спецификации fastcall от самих борландов требует передавать его в eax (от МС-а спецификация другая - там только ecx и edx). Однако разумней было бы модифицировать соглашение по аналогии с созданием thiscall и использовать ecx, потому что eax затирается многократно чаще любого другого регистра, а следовательно, Self почти всегда придется дополнительно хранить в другом регистре или памяти.
ТС уже подтвердил, что на деле используется eax. Теперь знаю, что делфийцы не заморачивались такими тонкостями.

a.n.d.r.e.w, как я и думал: mul Pos транслируется в mul cx, и делфа не обращает внимания на то, что cx затирается. А поскольку Pos по мнению делфы не используется, делфа его "оптимизирует", не создавая для него локальную переменную и не сохраняя в ней значение ecx. Впрочем, ничего удивительного.
Для подсчета смещений настоятельно рекомендую заменить этот mul на shl ecx, 2.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 20.11.2015 в 20:13.
Ответить с цитированием
Этот пользователь сказал Спасибо Bargest за это полезное сообщение:
a.n.d.r.e.w (20.11.2015)
  #10  
Старый 20.11.2015, 20:21
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
Для подсчета смещений настоятельно рекомендую заменить этот mul на shl ecx, 2
Спасибо. Учел. )
Наверное и вправду нечего полагаться на всякие Делфы ручками оно надежнее будет )))

если бы она не дописывала еще сама перед моим ассемблером строки с загрузкой значений регистров в стек и после строки с восстановлением стека так ваще былоб супер
поразбирался вот с ассемблером и многое стало понятно.
самоучка :-[
Ответить с цитированием
  #11  
Старый 20.11.2015, 20:24
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Цитата:
если бы она не дописывала еще сама перед моим ассемблером строки с загрузкой значений регистров в стек и после строки с восстановлением стека так ваще былоб супер
Раньше была такая директива, которая это и запрещала делать компилятору:
Код:
procedure MyProc(); assembler;
asm
...
end;
Но в новых делфях она уже давным-давно не работает.
Цитата:
Наверное и вправду нечего полагаться на всякие Делфы ручками оно надежнее будет
А вот ручное прописывание смещений при обращении к объектам - ОЧЕНЬ плохая практика. Просто фатальная. Лучше как раз пусть делфа их пересчитывает и подставляет в асм-код.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 20.11.2015 в 20:28.
Ответить с цитированием
  #12  
Старый 20.11.2015, 21:18
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

Цитата:
Сообщение от Bargest
А вот ручное прописывание смещений при обращении к объектам - ОЧЕНЬ плохая практика. Просто фатальная. Лучше как раз пусть делфа их пересчитывает и подставляет в асм-код.

ну не к объектам конечно. Адреса объектов передются вызывающей процедурой, как в моем случае в регистрах.
мы же говорим о стеке сейчас. чего сложного
запомнил ebp, выделил сколько нужно, натолкал туда своих переменных,
поработал, восстановил esp, ebp.
Я говорю о том чтобы не полагаться на явное использование переменных из описания процедуры, такие как эта злощастная Pos.
Ответить с цитированием
  #13  
Старый 20.11.2015, 21:23
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Цитата:
мы же говорим о стеке сейчас. чего сложного
Нет, я говорю про это:
Цитата:
mov edi, [eax+$04] //получилиSelf.fMemory
и подобное.
Да и при ручной записи переменной в стек на мой взгляд лучше бы использовать не cx, а Pos. Потому что если, например, когда-нибудь захочется изменить список аргументов процедуры, то придется проверять и переписывать весь код внутри нее и ловить море багов. Просто сохранить Pos, а не cx, в локальной переменной или другом регистре.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.

Последний раз редактировалось Bargest, 20.11.2015 в 21:27.
Ответить с цитированием
  #14  
Старый 20.11.2015, 21:26
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

ннннда..
ну тогда прийдется таки искать где отключается эта оптимизация.
вернулись с чего начали )
Ответить с цитированием
  #15  
Старый 20.11.2015, 21:30
Аватар для a.n.d.r.e.w
a.n.d.r.e.w a.n.d.r.e.w вне форума
Прохожий
 
Регистрация: 01.07.2015
Сообщения: 28
Версия Delphi: delphi xe7
Репутация: 10
По умолчанию

кстате self.fmemory она тоже "оптимизирует"
и что остается?
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 13:29.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter