Función de ensamblaje de Delphi que devuelve una cadena larga
Pregunta
Estoy intentando aprender programación ensambladora en línea en Delphi y, para ello, he encontrado Este artículo muy útil.
Ahora deseo escribir una función ensambladora que devuelva una cadena larga, específicamente una AnsiString
(por simplicidad).he 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;
Explicación:
Una función que devuelve una cadena tiene un carácter invisible. var result: AnsiString
(en este caso) parámetro, por lo que, al comienzo de la función, eax
debe contener la dirección de la cadena resultante.entonces puse edx
y ecx
al 3 y 1252, respectivamente, y luego llamar System._LStrSetLength
.En efecto, lo hago
_LStrSetLength(@result, 3, 1252)
donde 3 es la nueva longitud de la cadena (en caracteres = bytes) y 1252 es el estándar ventanas-1252 página de código.
Entonces, sabiendo que eax
es la dirección del primer carácter de la cadena, simplemente configuro la cadena en "ABC".Pero no funciona: me proporciona datos sin sentido o EAccessViolation.¿Cuál es el problema?
Actualizar
Ahora tenemos dos implementaciones aparentemente funcionales de myfunc
, uno que emplea NewAnsiString
y uno que emplea LStrSetLength
.No puedo evitar preguntarme si ambos son correctos, en el sentido de que no estropean el manejo interno de cadenas por parte de Delphi (recuento de referencias, liberación automática, etc.).
Solución
Tienes que usar algún 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;
Devolverá una cadena '210'...
Y siempre es una buena idea poner un bloque {$ifdef UNICODE} para que su código sea compatible con la versión de Delphi anterior a 2009.
Otros consejos
Con la excelente ayuda de A.Bouchez, logré corregir mi propio código, empleando 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;