From: Frank K. <fbk...@zy...> - 2010-04-05 10:18:32
|
Paul Procacci wrote: > Hello All, > > I'm a newbie at Nasm and trying to get my chops wet. In fact my asm > isn't stellar at all, but trying to learn it as a hobbyist. I've > decided to start off with a very simple subroutine, attempting to get > that working first but I'm running into lots of problems. I was able to > write my function in Gnu's Assembler which worked fine, however I don't > like it's syntax, hence the reason for attempting to write it in Nasm > which I like better. The c library function I am attempting to mimic is > bzero. In short it's "void bzero(char *addr, unsigned int len)". I > would have thought this would be quite easy but alas. > > ############################### > section .text > global bzero > ; void bzero(char *s, unsigned int len); > > bzero: > enter 0, 0 > .loop: > cmp [esp + 12], 0 ; If length is zero > je .done ; we are done > mov eax, [ebp + 8] ; Move address of pointer > into eax > mov [eax], 0 ; 0 out location > referenced in eax > add [ebp + 8], 1 ; add 1 to the address > sub [ebp + 12], 1 ; subtract 1 from > value of length > jp .loop ; continue with > loop > .done: > leave > ret > ############################### > > I've tried prefixing the some of the addresses with the keyword 'byte' > but that didn't help much either. (Ex: "add byte [ebp + 8], 1") Hi Paul, That's the right trick, although you'd want "dword" in that particular case. Gas, of course, has got the size built into the mnemonic - 'b' for "byte", 'w' for "word", and 'l' for "long", which Nasm calls "dword" (just so it won't be too easy). In many cases, Nasm can determine the size by the register specified... sometimes we just have to tell it. When we poke the zero into memory, we want just a byte. (optimization - do several bytes at once) But incrementing the pointer we'd need "add dword [ebp + 8], 1". Suppose our starting address was 0x8049200, and we did "add byte [ebp + 8], 1"... it would work up to 0x80492FF, but instead of going to 0x8049300, just the low byte would "roll over" - 0x8049200! Our routine would "work" much of the time, but would mysteriously fail if we crossed a 256 byte boundary. A good kind of bug to avoid!!! ;------------------------- section .text global bzero ; void bzero(char *s, unsigned int len); bzero: enter 0, 0 .loop: cmp dword [esp + 12], 0 ; If length is zero je .done ; we are done mov eax, [ebp + 8] ; Move address of pointer into eax mov byte [eax], 0 ; 0 out location referenced in eax add dword [ebp + 8], 1 ; add 1 to the address sub dword [ebp + 12], 1 ; subtract 1 from value of length jmp .loop ; continue with loop .done: leave ret ;--------------------------- Did you mean to use esp in that first reference to "length"? It'll work (but generates a longer instruction - oddity in the way instructions are encoded). I'd stick to ebp, throughout. Also, "jp" is "jump if parity even" - pretty sure you meant "jmp". This could perhaps be improved... After getting the address in eax, we don't need to update the parameter we were passed and reload eax each time through the loop. We could just load eax once, and increment it with "inc eax" (short) or "add eax, 1" (faster) or even "lea eax, [eax + 1]" (executes in the Address Generation Unit instead of the Arithmetic Logic Unit - potential speedup keeping them both occupied). We could also load the "length" into a register and manipulate the register instead of the memory location. If the memory location is "in cache" (which the stack would usually be), it's only a little faster to use a register than memory, but... I mentioned the possibility of zeroing more than one byte at once. What you'd do is check the low bits of the address to see it it's dword (or more) aligned - if not, do a byte at a time until it is - then do 4 (or 8? or more?) bytes at a time - do any odd bytes at the end one at a time. Worth it if the length is long... But get it working, first. http://www.agner.org when you're ready for optimization. :) > Also, I'd like to include the Gas example that did work that I'm trying > to convert into Nasm style syntax. > ############################### > bzero: > pushl %ebp > movl %esp, %ebp > .loop: > cmpl $0, 12(%ebp) > je .done > movl 8(%ebp), %eax > movb $0, (%eax) > addl $1, 8(%ebp) > subl $1, 12(%ebp) > jmp .loop > .done: > popl %ebp > ret > ############################### I find that Gas (AT&T) syntax "bothers" me a lot less as time goes on... (my taste-buds must be getting dull :) I still prefer Nasm! > If this is the wrong list, I apologize in advance and would like an > appropriate pointer to the correct list. This is the right list! I was specifically asked to create this list to keep this kind of question off the developer's list. As you can see, it doesn't get much traffic! Thanks for posting a message I can approve! (you won't have to wait for "moderation" after the first message) (you want to hit "reply all"! Just "reply" replies only to the poster) Another good place to ask questions (or share observations) is the shiny new Nasm forum: http://forum.nasm.us/ This replaces the SF forum, which had been "improved" beyond usability. Best, Frank |