Функция ассемблера Delphi, возвращающая длинную строку
Вопрос
Я пытаюсь изучить встроенное программирование на ассемблере в Delphi, и с этой целью я нашел Эта статья очень полезно.
Теперь я хочу написать функцию сборки, возвращающую длинную строку, в частности AnsiString
(для простоты).Я написал
function myfunc: AnsiString;
asm
// eax = @result
mov edx, 3
mov ecx, 1252
call System.@LStrSetLength
mov [eax + 0], ord('A')
mov [eax + 1], ord('B')
mov [eax + 2], ord('C')
end;
Объяснение:
Функция, возвращающая строку, имеет невидимый var result: AnsiString
(в данном случае) параметр, поэтому в начале функции eax
должен содержать адрес результирующей строки.затем я установил edx
и ecx
на 3 и 1252 соответственно, а затем позвоните System._LStrSetLength
.По сути, я делаю
_LStrSetLength(@result, 3, 1252)
где 3 — новая длина строки (в символах = байтах), а 1252 — стандартная. окна-1252 кодовая страница.
Тогда, зная, что eax
является адрес первого символа строки, я просто установил для строки значение «ABC».Но это не работает - мне выдает бредовые данные или EAccessViolation.В чем проблема?
Обновлять
Теперь у нас есть две, казалось бы, работающие реализации myfunc
, один нанимает NewAnsiString
и один, работающий LStrSetLength
.Я не могу не задаться вопросом, верны ли они оба, в том смысле, что они не портят внутреннюю обработку строк в Delphi (подсчет ссылок, автоматическое освобождение и т. д.).
Решение
Вы должны использовать что-то вроде:
function myfunc: AnsiString;
asm
push eax // save @result
call system.@LStrClr
mov eax,3 {Length}
{$ifdef UNICODE}
mov edx,1252 // code page for Delphi 2009/2010
{$endif}
call system.@NewAnsiString
pop edx
mov [edx],eax
mov [eax],$303132
end;
Он вернет строку «210»...
И всегда полезно добавить блок {$ifdef UNICODE}, чтобы ваш код был совместим с версией Delphi до 2009 года.
Другие советы
С превосходной помощью А. Буше мне удалось исправить свой собственный код, используя LStrSetLength
:
function myfunc: AnsiString;
asm
push eax
// eax = @result
mov edx, 3
mov ecx, 1252
call System.@LStrSetLength
pop eax
mov ecx, [eax]
mov [ecx], 'A'
mov [ecx] + 1, 'B'
mov [ecx] + 2, 'C'
end;