|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
||||
|
||||
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
|
||||
|
||||
Откуда взяты конструкции вроде
Цитата:
Особенно напрягает комментарий. При чем тут ebx? К чему я. Во-первых, ebp делфи может (если хочет!) ставить в совершенно произвольное значение, и вовсе не обязательно там будет указатель стекового фрейма. Во-вторых, у делфи FastCall, и уж что-то, а Self наверняка передается через регистр (вероятнее всего ecx). jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 17.11.2015 в 22:37. |
#3
|
||||
|
||||
конструкции эти создает сам компилятор
если поставить точку останова на начало функции и посмотреть сасемблированный компилятором код то можно увидеть Код:
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
|
||||
|
||||
В коде нового поста используется ebp + X, в старом - ebp - X. В [ebp + 4] по идее вообще адрес возврата, а туда записывается eax?. Что-то с этим новым кодом не так.
Теперь, почему Код:
mov edi, [eax+$04] //получилиSelf.fMemory Цитата:
Третье. Ты говоришь, что Цитата:
jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 19.11.2015 в 00:16. |
#5
|
||||
|
||||
Цитата:
все верно эт я по памяти писал снова ошибся, говорю ж не специалист в асм )), конечно смещение отрицательное. исправил пост. Попробую сначала. Разрабатываю класс для работы с большими числами до нескольких сотен десятичных знаков. Такие используются в криптографии. Хранится такое число кусками размером 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
|
||||
|
||||
Я бы на твоем месте все же посмотрел, во что транслируется эта команда "mul Pos". Потому что Pos - как ты сам говоришь, в регистре, а регистр затирается.
Только вот еще одна вещь. Цитата:
Что до оптимизации - не могу ничего сказать. Тут уже многое зависит от реализации самой делфы. Надо смотреть на сгенерированный ассемблерный код методов, чтобы понять, что не так. У меня, например, были случаи, когда VisualStudio при использовании встроенного ассемблера иногда не догадывалась сохранить регистры, или наоборот сохраняла их лишний раз и меняла тем самым все смещения от EBP. У делфи может быть то же самое в каких-то случаях. jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 20.11.2015 в 00:24. |
#7
|
||||
|
||||
Цитата:
Код:
foo.ToString(1, 2) Код:
ToString(foo, 1, 2) — Как тебя понимать? — Понимать меня не обязательно. Обязательно меня любить и кормить вовремя. На Delphi, увы, больше не программирую. Рекомендуемая литература по программированию |
#8
|
||||
|
||||
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)
|
#9
|
||||
|
||||
Цитата:
Наверное и вправду нечего полагаться на всякие Делфы ручками оно надежнее будет ))) если бы она не дописывала еще сама перед моим ассемблером строки с загрузкой значений регистров в стек и после строки с восстановлением стека так ваще былоб супер поразбирался вот с ассемблером и многое стало понятно. самоучка :-[ |
#10
|
||||
|
||||
Цитата:
Код:
procedure MyProc(); assembler; asm ... end; Цитата:
jmp $ ; Happy End! The Cake Is A Lie. Последний раз редактировалось Bargest, 20.11.2015 в 20:28. |