2012-02-17 4 views
3

다음 함수는 Delphi 2006에서 작동하지만 Delphi XE2에서는 RET을 처리 할 때 액세스 위반 오류 또는 권한있는 명령어 오류가 발생합니다.Delphi XE2 어셈블리

function Q_TrimChar(const S: string; Ch: Char): string; 
asm 
     PUSH ESI 
     MOV  ESI,ECX 
     TEST EAX,EAX 
     JE  @@qt 
     MOV  ECX,[EAX-4] 
     TEST ECX,ECX 
     JE  @@qt 
     PUSH EBX 
     PUSH EDI 
     MOV  EBX,EAX 
     MOV  EDI,EDX 
     XOR  EDX,EDX 
     MOV  EAX,ESI 
     CALL [email protected] 
     MOV  EDX,EDI 
     MOV  ECX,[EBX-4] 
@@lp1: CMP  DL,BYTE PTR [EBX] 
     JNE  @@ex1 
     INC  EBX 
     DEC  ECX 
     JNE  @@lp1 
     MOV  EDX,[ESI] 
     JMP  @@wq 
@@ex1: DEC  ECX 
@@lp2: CMP  DL,BYTE PTR [EBX+ECX] 
     JNE  @@ex2 
     DEC  ECX 
     JMP  @@lp2 
@@ex2: MOV  EDI,[ESI] 
     LEA  EDX,[EDI+ECX+1] 
@@lp3: MOV  AL,BYTE PTR [EBX+ECX] 
     MOV  BYTE PTR [EDI+ECX],AL 
     DEC  ECX 
     JNS  @@lp3 
@@wq: MOV  EAX,[ESI] 
     MOV  BYTE PTR [EDX],0 
     SUB  EDX,EAX 
     MOV  [EAX-4],EDX 
     POP  EDI 
     POP  EBX 
     POP  ESI 
     RET 
@@qt: MOV  EAX,ESI 
     CALL [email protected] 
     POP  ESI 
end; 

잘 모릅니다. 문제가 무엇입니까?

+1

그런데이 asm 코드는 방금 코딩되었습니다. 예를 들어, s 문자열이 Ch의 한 문자 일 경우 AV, IMHO를 만듭니다. 그것을 잊어 버리고 그의 대답에 마이크가 제공 한 2 번째 파스칼 버전을 사용하십시오. –

+1

이것이 너무 좁게 정의 되었기 때문에 나는 투표하기로 결심했다. 어떤 사람이 확실하게 대답 한 것 같아서 인상적이지만 사이트에 대한 이런 종류의 질문의 가치는 0과 같습니다. –

답변

17

나는 데이비드의 제안에 완전히 동의하며 파스칼에서 이것을 간단히 코딩하고 그 대답을 upvoted했습니다. 프로파일 링이 이것이 진정한 병목 현상이라고 지적하지 않으면 ASM이 실제로 필요하지 않습니다. 여기에 두 가지 버전이 있습니다. 첫 번째는 더 읽기 쉽지만 두 번째는 더 효율적입니다.

function Q_TrimChar(const S: string; Ch: Char): string; 
begin 
    result := S; 
    while (result <> '') and (result[1] = Ch) do Delete(Result, 1, 1); 
    while (result <> '') and (result[Length(Result)] = Ch) do Delete(Result, Length(Result), 1); 
end; 

function Q_TrimChar(const S: string; Ch: Char): string; 
var 
    First, Last : integer; 
begin 
    First := 1; 
    Last := Length(S); 
    while (First < Last) and (S[First] = Ch) do inc(First); 
    while (Last >= First) and (S[Last] = Ch) do Dec(Last); 
    Result := copy(S, First, Last-First+1); 
end; 
+1

+1 코드가 실제로 수행 한 작업을 위해 잘 수행됩니다. 두 번째 버전이 더 좋습니다. 명백한 최적화는 First = 1 및 Last = Length (S) 일 때 copy를 호출하지 않는 것입니다. –

+0

+1. 좋은 컴파일러 생성 문자열 조작 루틴은 특히 단순한 경우에는 두드리기가 어렵습니다. 나는 원래 어셈블러가 더 빠르다고 생각하지 않고 여기에 제 2 파스칼 변형을 제공한다고 생각하지 않는다! –

+0

@CosminPrund 맞습니다. 두 번째 버전은 원래 asm 버전보다 버그가 적으며, 같은 기능을 수행합니다. 즉, IMHO 버전이 버그 버전 (예 :'S = Ch') 인 경우 더 좋을 수도 있습니다. 진정한 최적화 된 asm 버전의 닫기 알고리즘에 대해서는 [this unit] (http://synopse.info/fossil/finfo?name=SynCommons)의 asm 및 pascal에서'function Trim (const S : RawUTF8) : RawUTF8;을 참조하십시오. .pas) - Delphi 2009/2010/XE/XE2 용으로 수정 된 John O'Harrow의 어셈블러를 사용했습니다. –

6

델파이 2006은 1 바이트 ANSI 문자를 사용하므로 stringAnsiString, CharAnsiChar입니다. Delphi 2009 및 이후 버전에서는 2 바이트 유니 코드 문자가 사용됩니다. 이 함수는 두 컴파일러 모두에서 작동하지 않을 수 있습니다.

AnsiString 및 AnsiChar를 사용하는 표준 해킹조차도 작동하지 않습니다. 대부분이 함수가 RTL 구현에 관해 가정하는 가정은 현대 델파이에서 더 이상 유효하지 않습니다.

나는이 함수를 파스칼에서 다시 작성하고 컴파일러가 작업하게 할 것이다. 이는 현재의 문제를 해결하는 가장 빠른 방법 일뿐만 아니라 64 비트 컴파일의 장애물을 해결할 수있을 것입니다.

+1

downvoter가주의를 돌 립니까? –

+2

제공된 코드의 주된 문제는 string/AnsiString 문제가 아니라 asm 블록 전체가 x64에서 작동하지 않는다는 것입니다. 다양한 레지스터 레이아웃과 * LStrFromPCharLen API의 새로운 서명으로 인해 Delphi 2009 이후. –

+1

@Arnaud 나는 그 비판이 다소 약하다는 것을 발견했다. x64가 포인트 옆에 있습니다. OP는 확실히 32 비트를 컴파일하고 있습니다. 이 코드는 32 비트 XE2에서 작동하지 않습니다. 32 비트 2010 또는 XE에서도 작동하지 않습니다. 게다가 x64 비트에 대해 언급 했으므로 이에 대해 설명했습니다. 그리고 주요 쟁점에 관해서는, 나는 그것을 전혀 사지 않습니다. 코드에 대한 하나의 문제는 작동하지 않는다는 것을 의미합니다. 따라서 코드에는 여러 가지 결함이 있습니다. 대답이 하나의 모든 문제를 식별하지 못하면 그것이 downvote의 가치가있게합니까? 눈부신 분명한 결론은 파스칼 변환이 필요하다는 것입니다. 깨진 코드를 과도하게 분석 할 필요가 없습니다. –