Função Assembly Delphi retornando uma string longa
Pergunta
Estou tentando aprender programação assembly inline em Delphi e, para isso, descobri Este artigo altamente útil.
Agora desejo escrever uma função assembly retornando uma string longa, especificamente um AnsiString
(Pela simplicidade).Eu tenho escrito
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;
Explicação:
Uma função que retorna uma string tem um invisível var result: AnsiString
(neste caso) parâmetro, então, no início da função, eax
deve conter o endereço da string resultante.Eu então configurei edx
e ecx
para 3 e 1252, respectivamente, e depois ligue System._LStrSetLength
.Com efeito, eu faço
_LStrSetLength(@result, 3, 1252)
onde 3 é o novo comprimento da string (em caracteres = bytes) e 1252 é o padrão janelas-1252 página de código.
Então, sabendo disso eax
é o endereço do primeiro caractere da string, simplesmente defino a string como "ABC".Mas não funciona - me fornece dados sem sentido ou EAccessViolation.Qual é o problema?
Atualizar
Agora temos duas implementações aparentemente funcionais de myfunc
, um empregando NewAnsiString
e um que emprega LStrSetLength
.Não posso deixar de me perguntar se ambos estão corretos, no sentido de que não atrapalham o manuseio interno de strings do Delphi (contagem de referências, liberação automática, etc.).
Solução
Você tem que usar algum tipo de:
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;
Ele retornará uma string '210' ...
E é sempre uma boa ideia colocar um bloco {$ifdef UNICODE} para ter seu código compatível com a versão do Delphi anterior a 2009.
Outras dicas
Com a excelente ajuda de A.Bouchez consegui corrigir meu próprio código, empregando 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;