Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 31.01.2011, 05:17   #1
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию Странное поведение BASM (использование неиспользуемых регистров компилятором)

Пытаюсь создать свой собственный объект. Объект очень простой. Под него только выделяется память и записывается в первые четвре байта класс. Не спрашивайте зачем. Просто, маюсь вигней, заодно тренеруюсь на basm'е. И вот че увидел и не могу понять.

Есть код:
Код:
class function TMyObject.NewInstance: TObject;
begin
{$IFDEF PUREPASCAL}
  Result := Sib_GetMem (PInteger (Integer(Self) + vmtInstanceSize)^);
  PInteger(Result)^ := Integer(Self);
{$ELSE}
asm
        PUSH EAX           // Сохранение адреса класса (Self)
        MOV EAX, [EAX-$28] // Размер объекта (vmtInstanceSize = $28)
        CALL Sib_GetMem    // Выделение памяти
        POP [EAX]          // Запись Self в адрес нового объекта
end;
{$ENDIF}
end;
А вот как этот же код выглядит в окне CPU:
Цитата:
MySystem1.pas.97: PUSH EAX // Сохранение адреса класса (Self)
0044FAD4 50 push eax
MySystem1.pas.98: MOV EAX, [EAX-$28] // Размер объекта (vmtInstanceSize = $28)
0044FAD5 8B40D8 mov eax,[eax-$28]
MySystem1.pas.99: CALL SIb_GetMem // Выделение памяти
0044FAD8 E8ABFFFFFF call Sib_GetMem
MySystem1.pas.100: POP [EAX] // Запись Self в адрес нового объекта
0044FADD 8F00 pop dword ptr [eax]
0044FADF 8BC2 mov eax,edx
MySystem1.pas.103: end;
0044FAE1 C3 ret
0044FAE2 8BC0 mov eax,eax
Вот это
Цитата:
mov eax,eax
я еще могу понять. Он стоит после RET и до него дело не дойдет.

Но зачем
Цитата:
pop dword ptr [eax]
Он и так уже dword. Зачем здесь приведение типов? И как компилятору сказать, чтобы он этого не делал?

А вот это вообще меня убило
Цитата:
mov eax,edx
Точнее не меня, а мой код. После выхода из функции в EAX уже не то, что нужно. Откуда вообще эта строчка взялась?
Пришлось сделать так

Код:
asm
        PUSH EAX           // Сохранение адреса класса (Self)
        MOV EAX, [EAX-$28] // Размер объекта (vmtInstanceSize = $28)
        CALL Sib_GetMem    // Выделение памяти
        POP [EAX]          // Запись Self в адрес нового объекта
        RET
end;
В CPU стало
Цитата:
MySystem1.pas.97: PUSH EAX // Сохранение адреса класса (Self)
0044FAD4 50 push eax
MySystem1.pas.98: MOV EAX, [EAX-$28] // Размер объекта (vmtInstanceSize = $28)
0044FAD5 8B40D8 mov eax,[eax-$28]
MySystem1.pas.99: CALL Sib_GetMem // Выделение памяти
0044FAD8 E8ABFFFFFF call Sib_GetMem
MySystem1.pas.100: POP [EAX] // Запись Self в адрес нового объекта
0044FADD 8F00 pop dword ptr [eax]
MySystem1.pas.101: RET
0044FADF C3 ret
0044FAE0 8BC2 mov eax,edx
MySystem1.pas.104: end;
0044FAE2 C3 ret
0044FAE3 90 nop
Но теперь все работает нормально.

Я asm совсем недавно начал изучать. В чем особеность такой компиляции. Ведь я ему уже дал готовый код на ассемблере. Зачем он его так, на мой взгляд не логично, исправил?

Последний раз редактировалось Sibedir; 31.01.2011 в 09:06.
Sibedir вне форума Ответить с цитированием
Старый 31.01.2011, 07:17   #2
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Цитата:
Он и так уже dword
Кто он? Со стека можно взять и word, например. Откуда компилятор знает, что у вас там в [eax] поинтер ожидается? Ведь могло быть и так:

Код:
POP word ptr [EAX]
Но раз вы поленились указать размер операнда, компилятор молча взял dword, надеясь на лучшее.

Цитата:
Откуда вообще эта строчка взялась?
Что значит откуда? А result типа TObject кто будет возвращать? Т.к. оптимизация у вас включена, то компилятор решил хранить result в edx. Если оптимизацию отключить, это будет стек.

Код:
00450871 8B45F8           mov eax,[ebp-$08]
Кстати, вам же ворнинг наверняка выдало:

Цитата:
[Warning] Unit1.pas(81): Return value of function 'myObj.NewInstance' might be undefined
Это ведь не просто так ) Добавьте строчку

Код:
mov result, eax
перед выходом и всё будет пучком. Можете потом проверить, во что откомпилится эта строчка при включенной и выключенной оптимизации.

Да, и если хотите совсем уж всё держать под контролем, то функцию можно объявить так:

Код:
function foo(param: integer): pointer; assembler;
asm
end;
Тогда компилятор не будет ничего своего добавлять.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."

Последний раз редактировалось veniside; 31.01.2011 в 07:22.
veniside вне форума Ответить с цитированием
Старый 31.01.2011, 08:31   #3
GunSmoker
Старожил
 
Регистрация: 13.08.2009
Сообщений: 2,581
По умолчанию

Цитата:
Откуда вообще эта строчка взялась?
Это твой begin и end.

Цитата:
Да, и если хотите совсем уж всё держать под контролем, то функцию можно объявить так:

Код:
function foo(param: integer): pointer; assembler;
Цитата:
The reserved word inline and the directive assembler are maintained for backward compatibility only. They have no effect on the compiler.
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
GunSmoker вне форума Ответить с цитированием
Старый 31.01.2011, 08:52   #4
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

С dword понял. Он ведь его не в регистр, а в пямять загоняет. Потому и не знает размер. Спасибо.
Остальное поведение компилятора остается за гранью моего понимания.

Цитата:
Что значит откуда? А result типа TObject кто будет возвращать?
Вообще Result = eax.

Цитата:
Т.к. оптимизация у вас включена, то компилятор решил хранить result в edx.
Если бы он решил, что result = edx, тогда бы он в делал
Код:
mov edx, ?
и в вызывающей процедуре обращался бы к edx. А он там именно к eax обращается.
Особо прошу обратить ваше внимание на тот факт, что edx в теле обсуждаемой процедуры никак не определено. Тоесть вообще никак.
Код:
0044FADF 8BC2 mov eax,edx
Это единственная строчка в коде с регистром edx. Что же он тогда пытается записать в eax?

Цитата:
Кстати, вам же ворнинг наверняка выдало:
Ну да. Я тогда не пойму, зафигом нужно соглашение о том, что result=eax. Ну да Бог с ним с предупреждением. В итоге в eax хранится именно то, что нужно (если вовремя сделать ret), а в вызываемой процедуре используется именно eax.

Цитата:
Код:
function foo(param: integer): pointer; assembler;
А в справке delphi сказано, что assembler устаревшее ключевое слово, и оставлено, только для обратной совместимости.
...
И действительно, ни чего не поменялось (Delphi 7).

Цитата:
Сообщение от GunSmoker
Это твой begin и end.
А-а-а. Ура. Спасибо. Совсем забыл поместить begin...end внутрь условия. Теперь так:
Код:
class function TMyObject.NewInstance: TObject;
{$IFDEF PUREPASCAL}
begin
  Result := Sib_GetMem (PInteger (Integer(Self) + vmtInstanceSize)^);
  PInteger(Result)^ := Integer(Self);
end;
{$ELSE}
asm
        PUSH EAX            // Сохранение адреса класса (Self)
        MOV EAX, [EAX-$28]  // Размер объекта (vmtInstanceSize = $28)
        CALL Sib_GetMem     // Выделение памяти
        POP DWORD PTR [EAX] // Запись Self в адрес нового объекта
end;
{$ENDIF}
и все работает как надо.

Последний раз редактировалось Sibedir; 31.01.2011 в 08:56.
Sibedir вне форума Ответить с цитированием
Старый 31.01.2011, 10:03   #5
GunSmoker
Старожил
 
Регистрация: 13.08.2009
Сообщений: 2,581
По умолчанию

Цитата:
Я тогда не пойму, зафигом нужно соглашение о том, что result=eax
Это соглашение на уровне ассемблера. У тебя - НЕ ассемблерная процедура (была). И это соглашение к ней неприменимо. У тебя обычная паскалевская процедура. Что значит, что у неё есть Result и его надо ставить, а не EAX.
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
GunSmoker вне форума Ответить с цитированием
Старый 31.01.2011, 10:56   #6
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Еще раз спасибо. Вкупаюсь потихоньку.
Sibedir вне форума Ответить с цитированием
Старый 31.01.2011, 11:37   #7
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Ну да, assembler; можно не указывать, старая привычка. Главное, начинать код с asm, а не begin.

Цитата:
Вообще Result = eax.
Вобще result — это локальная переменная, неявно объявляемая в каждой функции (кроме ассемблерных). Поэтому в EAX из этой переменной в конце функции и загружается значение, которе будет возращено.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Старый 31.01.2011, 11:53   #8
Sibedir
Тот ещё
Старожил
 
Аватар для Sibedir
 
Регистрация: 14.11.2007
Сообщений: 2,242
По умолчанию

Ага, ага. Я всё записываю.
Ну я, короче, понял уже. Во время begin компилятор решил, что result'ом будет edx. Я это благополучно проигнорировал и в итоге получил "странную" строчку.

Слушайте, а зачем после ret
Цитата:
mov eax,eax
Это, кстати, часто встречается. Ну обнуление
Цитата:
xor eax,eax
я еще могу понять. Но здесь-то зачем никогда регистр сам в себя пишется. Это чё, типа расширенный nop?

Последний раз редактировалось Sibedir; 31.01.2011 в 11:57.
Sibedir вне форума Ответить с цитированием
Старый 31.01.2011, 12:02   #9
veniside
Старожил
 
Регистрация: 03.01.2011
Сообщений: 2,508
По умолчанию

Цитата:
Сообщение от Sibedir Посмотреть сообщение
Это чё, типа расширенный nop?
да, это так называемый align, чтобы следующая после него команда следовала с нужного адреса (выравненого по двойному слову, например). два nop не так круто, вот создатели компиляторов и изголяются. Возможно, два nop как-то хуже влияют на предвыборку, чем одна команда mov, не знаю.
"Когда приходит положенное время, человек перестаёт играть в пинбол. Только и всего."
veniside вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Странное поведение realloc eraserhp Общие вопросы C/C++ 7 17.05.2010 09:52
Странное поведение realloc eraserhp Помощь студентам 0 15.05.2010 18:06
Странное поведение gets alex_alpha Общие вопросы C/C++ 3 27.03.2010 18:21
Странное поведение null Vitalyk JavaScript, Ajax 6 13.02.2010 15:22