Copy Function in Delphi XE3


I came across a very strange problem when I tried to use Copy function in Delphi XE3. The  Copy function behaves differently for string when compiled into 32bit and 64bit using Delphi XE3. I have asked the question on stackoverflow.com and it is no surprise that this was a bug and has been fixed by patch update 1.

In short, the Copy function takes a third parameter as the Count which can be omitted. If omitted, the characters till the end of the string will be copied. However, when compiled to 64-bit, it will actually copy nothing. Let’s take a look at the following code.

copy Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

When compiled to 32-bit (using Delphi XE3), the above will print correct result, which is 234567890 followed by its length, which is 9.

However,  when same code compiled to 64-bit, it will actually print a blank line (empty string), and the following zero indicates the Copy returns empty string.

Let’s take a look at how the assembly code is actually generated by the compiler. When 32-bit EXE is targeted, the following assembly could be observed. (Setting a breakpoint and press Ctrl+Alt+D to see the dis-assembly).

copy1 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

From above, we can see that when its third parameter is omitted, in fact a length count with $7FFFFFF, which is the maximum signed integer representation is fed into the compiler magic function UStrCpy. The Compiler will actually check the type of the string and invokes corresponding copy function. Register EAX stores the address of the source string; The Register EDX stores the second parameter: the index of the string to copy and the Register ECX stores the third parameter, which is the count of characters to copy.

However, without patches, the Delphi XE3 compiler is buggy when generating 64-bit EXE.

copy-64-error Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

So without patches, we can quickly replace such code with the third parameter set explicitly to $7FFFFFFF if you want to copy to the end of the string. This should be ok because if you take a look that the compiler-magic copy functions in System unit, you will find that the Count is actually checked with the maximum number of characters that can be copied. So if Count is much bigger than the length of the string, only the characters left to the end will be copied.

copy3 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

The above shows the code generated by Delphi XE3 64-bit, which explicitly gives the Count parameter, the same code should be generated if the third parameter is omitted. We can see that Register r8d (lower 32-bit) is used for passing the index. Register r9d (lower 32-bit) is used for passing the Count.

copy4 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

For 32-bit EXE, it gives the same assembly code with or without the third parameter set to $7FFFFFFF.

Another workaround is to explicitly compute the number of characters needed to copy, like the following. But it is not suggested since extra unnecessary computation will be occurred.

copy7 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

The above code computes the number of characters left to copy base on the length, and this will actually generate unnecessary code like this.

copy5 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

The above shows clearly in 32-bit code, the length will be obtained for its third parameter. Similarly in 64-bit code, the final Count value is computed and stored in Register r9d.

copy6 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

In fact, the form of code like Copy(s, a, Length(s) – (a – 1)) can be speed up by using constant $7FFFFFFF, which is a lot faster. Since the Count will be checked, shown below from the compiler-magic string copy functions in System unit.

copy8 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows
copy9 Copy Function in Delphi XE3 64 bit assembly language bug fixes code compiler delphi implementation interpreter / compiler optimization programming languages technical tricks windows

References:

1. http://qc.embarcadero.com/wc/qcmain.aspx?d=113805

2. http://stackoverflow.com/questions/16142544/why-copy-function-behaves-differently-in-64-bit-delphi-xe3

3. http://www.codeproject.com/Articles/262819/Finally-64-Bit-Delphi-is-here-and-with-64-Bit-BASM

4. http://msdn.microsoft.com/en-us/library/windows/hardware/ff561499(v=vs.85).aspx

–EOF (The Ultimate Computing & Technology Blog) —

GD Star Rating
loading...
1014 words
Last Post: Add Formatted Text to Word from VBScript
Next Post: How to use align-data-move SSE in Delphi XE3 ?

The Permanent URL is: Copy Function in Delphi XE3

Leave a Reply