Skip to content

Instantly share code, notes, and snippets.

@faissaloo
Last active March 19, 2016 18:47
Show Gist options
  • Save faissaloo/e28b55b0e4671132f522 to your computer and use it in GitHub Desktop.
Save faissaloo/e28b55b0e4671132f522 to your computer and use it in GitHub Desktop.
Custom strlen function in Assembly
;==================================MIT LICENCE=================================
; Copyright (c) 2016 Faissal Bensefia
;
; Permission is hereby granted, free of charge, to any person obtaining a copy
; of this software and associated documentation files (the "Software"), to deal
; in the Software without restriction, including without limitation the rights
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
; copies of the Software, and to permit persons to whom the Software is
; furnished to do so, subject to the following conditions:
;
; The above copyright notice and this permission notice shall be included in all
; copies or substantial portions of the Software.
;
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
; SOFTWARE.
;===============================================================================
;==================================INFORMATION==================================
; Name: _strlen
; Usage:
; mov ebx, (STRING START)
; call _strlen
; Returns:
; ecx = The string length
; edi = The string end position in memory
; Description:
; Originally written for NASM.
; This is a string length function for assembly based on the algorithm in glibc's
; strlen.c. It is considerably faster than other, more usual, pure-assembly
; implementations of strlen. It takes a string one dword at a time rather than
; one byte at a time and then performs some strange maths on it which will turn
; all 0s in a string into 0x80s and all other characters into 0x00s.
; For example:
; A word from our string: 00474d43
; Gets turned into: 80000000
; Also, note that this is written for 32-bit assembly, 64-bit may allow you to
; do this faster by taking a quad word each time and then
; comparing it with 0x80 to 0x80000000000000 and using the r* registers instead
; as opposed to what we're doing for 32-bit which is 0x80 to 0x800000 and using
; the e* registers.
;===============================================================================
_strlen:
mov edi, ebx ;Initialise scasw with the value passed to us in ebx
;We're not getting the coder to send it directly to edi because we're still
;going to need to get the difference between them later to determine the
;actual length
xor ecx, ecx ;Fast way to set ecx to 0
_s:
mov ecx,[edi] ;edi holds the pointer to the word in memory, so copy that word in memory to ecx so we can use it
add edi,4 ;Move to the next 'word'+1 (because we'll be decreasing from it)
and ecx, 0x7F7F7F7F ;Masks out the highest bit of each byte (char), to ENSURE that byte level overflows from the subtraction will not propagate beyond the highest bit.
;These are the 'magic numbers' ripped from glibc
sub ecx, 0x01010101
and ecx, 0x80808080
xor ecx, 0 ;Compare ecx with 0, if ecx is 0 it means that there are no NULL characters in it
jz _s ;If none of them were zeros loops back to s
;otherwise let's track down the one that was zero which will be represented a 0x80
sub edi, 4 ;Remove the 'add edi, 4' that we did before
; mov edx again, so that we can test the actual value, since our cool magic
; number stuff that we did before destroys edx, which means that character
; 128 will cause misfires
mov ecx,[edi]
test ecx, 0xFF
jz _strlenEnd
inc edi
test ecx, 0xFF00
jz _strlenEnd
inc edi
test ecx, 0xFF0000
jz _strlenEnd
inc edi
test ecx, 0xFF000000
jnz _strlenEnd ;If it was a misfire, go back and continue
_strlenEnd:
sub edi, ebx ;Get the difference
ret
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment