50 lines
1.3 KiB
Plaintext
50 lines
1.3 KiB
Plaintext
DYNASM RevStr(BYVAL s AS STRING) AS STRING
|
|
// get length of string
|
|
// divide by two
|
|
// setup pointers to head and tail
|
|
// iterate from 1 to (length \ 2)
|
|
// swap head with tail
|
|
// increment head pointer
|
|
// decrement tail pointer
|
|
|
|
ENTER 0, 0 // = PUSH EBP: MOV EBP, ESP
|
|
PUSH EBX // by Windows convention EBX, EDI, ESI must be saved before modification
|
|
|
|
MOV EAX, s // get string pointer
|
|
MOV ECX, EAX // duplicate it
|
|
|
|
.WHILE BYTE PTR [ECX] <> 0
|
|
|
|
INC ECX // propagate to tail
|
|
|
|
.WEND
|
|
|
|
MOV EDX, ECX // duplicate tail pointer
|
|
DEC EDX // set it to last byte before trailing zero
|
|
|
|
SUB ECX, EAX // get length in ECX in 1 CPU cycle
|
|
SHR ECX, 1 // get length \ 2 in 1 CPU cycle; that's the beauty of power-of-two division
|
|
|
|
.WHILE ECX > 0
|
|
|
|
MOV BL, [EDX] // no need to XOR; just overwrite BL and BH contents
|
|
MOV BH, [EAX] // DynAsm deduces data size from destination register sizes
|
|
|
|
MOV [EDX], BH // ditto, source register sizes
|
|
MOV [EAX], BL
|
|
|
|
INC EAX // propagate pointers
|
|
DEC EDX
|
|
|
|
DEC ECX // decrement counter
|
|
|
|
.WEND
|
|
|
|
// point to start of string again
|
|
MOV EAX, s // MOV = 1 CPU cycle, PUSH + POP = 2 CPU cycles
|
|
|
|
POP EBX // by Windows convention ESI, EDI, EBX must be restored if modified
|
|
LEAVE // = POP EBP
|
|
RET
|
|
END DYNASM
|