Memory Initializaiton

Tight_Coder_Ex 0 Tallied Votes 217 Views Share

These are a pair of routine I use quite often. I know MemSet is virtualy the same as ZeroMemory in kernel32.dll, but there may be a time I want to use these in an embedded system where this dll won't be avaliable.

;			         *** INITIALIZE PROCEDURE FRAME ***

; Many times routines need local variables that are usually saved on the stack.  At times it
; is convenient to have this space intialized to nulls.

;	ENTRY:	EBP 	= Top of procedure frame
;		ESP + 4 = Bottom of frame

;	LEAVE:	EAX	= 0
;		ECX 	= Size of procedure frame
;		EDX	= Base pointer to fill area.

  InitFrame	xor	eax, eax
		mov	ecx, ebp		; Top of area
		mov	edx, esp		; Bottom of area
		add	edx, byte 4		; Allow for callers return
		sub	ecx, edx		; Calculate size of frame

; Now we can just fall into MemSet to fill procedure frame.

; ============================================================================================
; 					*** MEMORY SET ***

;	ENTRY:	EAX = Fill pattern (32 bit).
;		ECX = Total number of bytes to initialize.
;		EDX = Base pointer to fill area.

;	LEAVE:	All registers preserved.

; NOTE: If EAX is not evenly divisible by 4 then all 4 bytes of EAX must be the same,
;	otherwise last 1, 2 or 3 bytes of buffer will only be fill with AL.

  MemSet	push	edi
		push	ecx			; Preserve registers
		push	edx

		mov	edi, edx		; Set destination index.
		mov	 dl,  cl		; Save LSB of counter
		shr	ecx, 2			; Number of dwords that can be written
		cld				; Assure EDI will auto increment with STOS
		rep	stosd
		mov	 cl,  dl
		and	 cl,  3			; Is buffer evenly divisible by 4
		jz	.Done			; ZR = 1, if so.

		rep	stosb			; Write odd numbered bytes

  .Done		pop	edx
		pop	ecx			; Restore registers
		pop	edi
		ret

Dani AI

Generated

Nice, compact routines — thanks to for posting them and to for the nod. A few practical notes and small improvements that clarify edge cases and make the code more robust and faster on real hardware.

First, make the frame-size check explicit. If EBP is less than or equal to ESP+4 there’s nothing to clear; skipping the fill avoids wrapping the length calculation. Also ensure the direction flag is cleared (CLD) before any REP STOS* (the posted routine already does this — it’s a good habit to keep).

Performance tips: REP STOSD is fast for large, dword-aligned blocks but suffers on unaligned destinations. Best practice is:

  • write a few leading bytes until the destination is 4‑byte aligned,
  • then use REP STOSD for the bulk,
  • finish with REP STOSB for the tail.

When the fill value is a single byte, build a 32‑bit or 64‑bit repeated pattern once and use the wide store. Example (C-style):

uint32_t p32 = (uint8_t)b * 0x01010101u;
uint64_t p64 = (uint8_t)b * 0x0101010101010101ULL;

Caveat about arbitrary 32‑bit patterns: if EAX holds a multi‑byte pattern that is not the same in each byte, the current method will leave the final 1–3 bytes filled with AL only. Options are to (a) use byte stores only for correctness, (b) copy the pattern manually for the tail, or (c) prepare a rotated/mirrored dword sequence so the tail bytes match the intended pattern.

Portability note: on x86‑64 use RDI/RCX/RAX and REP STOSQ for 8‑byte stores and respect the platform’s calling convention and stack alignment. Finally, test with zero/very small frame sizes, unaligned frame bases, and varied fill patterns to verify both correctness and performance across targets.

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Tight_Coder_Ex
nice to see the Grandfather of it all appear!! Thanks!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.