[fpc-pascal] Re: assign code to a method
The correct statement is therefore: Move(functionCode[1], FBlock^.code^, len); It would also be cleaner to use a dynamic array instead of a string to store arbitrary binary data (in that case, you'd have to use functionCode[0] above though). I have tried yours and other combinations. The following one works at last in Delphi6 PE. This will keep me occupied some time updating my 32 bits programs, so that they will be DEP safe. Thanks to you all. Note that I have dropped the use of Move. As for fpc-Lazarus 64 bits, it does not work yet: more about this in another thread. {--code snippet begins--} len:= Length(cod); { cod is the ansiString containing the opcodes to be executed} SetLength(ba, len); { ba is an auxiliary array of bytes} for i:= 0 to len-1 do ba[i]:= ord(cod[i+1]); { exeBlock has been declared as PChar } exeBlock:= VirtualAlloc(nil, len + SizeOf(exeBlock), MEM_COMMIT, PAGE_EXECUTE_READWRITE); for i:= 0 to len-1 do exeBlock[i]:= chr(ba[i]); @F:= @exeBlock[0]; { F is the function whose code is here assigned to cod} ba:= nil; cod:= ''; {--code ended---} For people interested in details: the use of an AnsiString for storing the opcodes, that is for building cod, eases this by the use of the special procedures to treat strings (adding them, etc.). The use of exeBlock as PChar serves to guarantee that a contiguous chunk of memory starting in exeBlock[0] becomes reserved for the exclusive use of exeBlock and cannot overlap another variable: this is my interpretation of the failure that did happen when, after assigning the code to F, I did put cod = ''. -- montesin at uv dot es ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
[fpc-pascal] Re: assign code to a method
Many thanks, Andrew. I intend to apply this to my old programs in 32 bit Windows. I'll tell you about the outcome. Below you will see a console application for testing your suggestions or better my understanding of them. The results are (in Windows XP 64 bits Pro): 1. When Data Execution Prevention (DEP) is enforced, the program fails. 2. When DEP is enforced only for essential Windows programs, the program functions (that is, it writes the value of pi). But if one uncomments the commented line of code, that is makes codeFunction:= '', the program fails. What may be happening here? Many thanks -- montesin at uv dot es {--begins code for console app--} program Test_VirtualAlloc; {$APPTYPE CONSOLE} uses SysUtils, Types, Windows; type PCodeBlock= ^CodeBlock; CodeBlock = record size: DWord; code: Pointer; end; RealFunction = function(const X : array of Extended) : Extended; TOpCodeFunctionExtended = class(TObject) private functionCode : AnsiString; {the function opCode sequence} public F : function(const X : array of Extended) : Extended; FBlock: PCodeBlock; constructor Create; destructor Destroy; override; end; var theF: TOpCodeFunctionExtended; rslt: Extended; linetxt: AnsiString; constructor TOpCodeFunctionExtended.Create; var len: Integer; begin inherited; {execution of this puts pi in the register st(0) of FPU} functionCode:= #$55 + {push ebp} #$8B#$EC +{mov ebp, esp} #$D9#$EB +{fldpi} #$C9 +{leave} #$C3; {ret} len:= Length(functionCode); FBlock:= VirtualAlloc(nil, len + SizeOf(codeBlock), MEM_COMMIT, PAGE_EXECUTE_READWRITE); Move(functionCode, PChar(FBlock^.code), len); FBlock.size:= len; @F := FBlock^.code; {assignation of code to the function} //functionCode:= ''; {if this is uncommented, program fails} end; destructor TOpCodeFunctionExtended.Destroy; begin if FBlock nil then begin VirtualFree(FBlock, 0, MEM_RELEASE); FBlock:= nil; end; theF.Free; inherited end; begin theF:= TOpCodeFunctionExtended.Create; Writeln('Enter a character. For exiting, enter an ''x'''); Writeln; try repeat readln(linetxt); if linetxt 'x' then begin rslt:= theF.F([]); writeln(FloatToStrF(rslt, ffFixed, 18, 18)); end; until linetxt = 'x'; except on exception do ; end; end. {--ends code for console app--} ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Re: assign code to a method
On 22 Feb 2011, at 21:24, Angel Montesinos wrote: one uncomments the commented line of code, that is makes codeFunction:= '', the program fails. What may be happening here? This code is wrong: functionCode : AnsiString; {the function opCode sequence} ... Move(functionCode, PChar(FBlock^.code), len); An ansistring is a pointer. Move takes formal const/var parameters. So the move() moves the pointer along with whatever data comes after it over the FBlock^.code pointer and whatever data comes after that. What you want, is to move the data to which functionCode points into the memory block to which FBlock^.code points. The correct statement is therefore: Move(functionCode[1], FBlock^.code^, len); It would also be cleaner to use a dynamic array instead of a string to store arbitrary binary data (in that case, you'd have to use functionCode[0] above though). Jonas___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Re: assign code to a method
I second the motion of using a Dynamic array too instead of the manual creation/destruction of a memory block. I use this for a virtual machine I created a few years back and it works under XP/Vista for me :) cheers, Paul - Original Message - From: Jonas Maebe jonas.ma...@elis.ugent.be To: FPC-Pascal users discussions fpc-pascal@lists.freepascal.org Sent: Wednesday, February 23, 2011 7:54 AM Subject: Re: [fpc-pascal] Re: assign code to a method On 22 Feb 2011, at 21:24, Angel Montesinos wrote: one uncomments the commented line of code, that is makes codeFunction:= '', the program fails. What may be happening here? This code is wrong: functionCode : AnsiString; {the function opCode sequence} ... Move(functionCode, PChar(FBlock^.code), len); An ansistring is a pointer. Move takes formal const/var parameters. So the move() moves the pointer along with whatever data comes after it over the FBlock^.code pointer and whatever data comes after that. What you want, is to move the data to which functionCode points into the memory block to which FBlock^.code points. The correct statement is therefore: Move(functionCode[1], FBlock^.code^, len); It would also be cleaner to use a dynamic array instead of a string to store arbitrary binary data (in that case, you'd have to use functionCode[0] above though). Jonas___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
[fpc-pascal] Re: assign code to a method
El 18/02/2011 13:46, Sven Barth escribió: I personally would say that mapping a page with the Execute flag set and storing the to-be-executed content there should be enough. After all JIT compilers must do that as well. ;) Thanks. I shall study this issue. -- montesin at uv dot es ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal
[fpc-pascal] Re: assign code to a method
El 18/02/2011 17:59, Andrew Haines escribió: From the other comments it seems like you are writing some assembly to memory at runtime then calling that code? That is right. If so then maybe the following can help you. ...code... so the usage would be like so function TTrampolineManager.GenerateCode(args: ): Pointer; begin try Result := CurrentBlock.Position; // = @Block + Block.Cursor repeat WriteData(your_data, size_of_data); until done; except on e: TrampolineBlockFullException do begin TrampolineManager.AllocateBlock; Result := GenerateCode(args); end; end; end; Hope this helps :) A lot! I understand that for purposes other than trampolining, the essence of this is the the way of building an almost contiguous list, say Block: array[0..lastCodePiece] of Pointer; of DEP executable codes inside an authorized chunk of memory, and that the call for assigning one of them, Block[i], to some function declared as otherObject.thisFunction(other args): Double; would be @otherObjectInstance.thisFunction:= Block[i]; And also the way to obtain another block when one of them has been exhausted, and the way of disposing of them, right? Many thanks, Andrew. I intend to apply this to my old programs in 32 bit Windows. I'll tell you about the outcome. -- montesin at uv dot es ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal