![]()  | 
	
 
  | 
		
			
  | 	
	
	
		
		|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны | 
![]()  | 
	
	
| 
		 | 
	Опции темы | Поиск в этой теме | Опции просмотра | 
| 
	 | 
| 
		 
			 
			#1  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Привет форум! 
		
	
		
		
		
		
		
	
		
		
	
	
	Появилось желание некоторые функции в делфи переписать на ассемблере. Я не большой спец по ассемблеру, да собственно и не в нем вопрос. Есть такая вот функция, и сам код работает если взять асм блок в 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). Последний раз редактировалось 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 Цитата: 
	
 Третье. Ты говоришь, что Цитата: 
	
 Последний раз редактировалось 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. У делфи может быть то же самое в каких-то случаях. Последний раз редактировалось Bargest, 20.11.2015 в 00:24.  | 
| 
		 
			 
			#7  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Код: 
	foo.ToString(1, 2) Код: 
	ToString(foo, 1, 2)  | 
| 
		 
			 
			#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. Последний раз редактировалось Bargest, 20.11.2015 в 20:13.  | 
| Этот пользователь сказал Спасибо Bargest за это полезное сообщение: | ||
 
a.n.d.r.e.w (20.11.2015)
  | ||
| 
		 
			 
			#9  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Наверное и вправду нечего полагаться на всякие Делфы ручками оно надежнее будет ))) если бы она не дописывала еще сама перед моим ассемблером строки с загрузкой значений регистров в стек и после строки с восстановлением стека так ваще былоб супер поразбирался вот с ассемблером и многое стало понятно. самоучка :-[  | 
| 
		 
			 
			#10  
			
			
			
			
		 
		
		
	 | 
||||
		
		
  | 
||||
| 
	
	
		
			
			 Цитата: 
	
 Код: 
	procedure MyProc(); assembler; asm ... end; Цитата: 
	
 Последний раз редактировалось Bargest, 20.11.2015 в 20:28.  |