Outb; can you explain why one function works and one doesn't

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Outb; can you explain why one function works and one doesn't

Post by Puffy »

Hey,

I tried writing my own outb function in asm, and I came up with this:

Code: Select all

out_port_byte:
	pushl	%ebp
	movl	%esp, %ebp
	movw	6(%ebp), %dx
	movb	7(%ebp), %al
	outb	%al, %dx
	popl	%ebp
	ret
That code doesn't work.

I then compiled one of the many examples of outb (that use inline asm in C) with GCC and I looked at the resulting code, it produces this:

Code: Select all

out_port_byte:
	pushl	%ebp
	movl	%esp, %ebp
	movzwl	8(%ebp), %edx
	movzbl	12(%ebp), %eax
	outb 	%al, %dx
	popl	%ebp
	ret
Now that does work. However, I can't understand why my code doesn't work and that this code does. Can anyone explain?

Cheers,

Puff
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Re: Outb; can you explain why one function works and one doesn't

Post by pcmattman »

Yours doesn't work because your offsets are wrong:

Code: Select all

   movw   6(%ebp), %dx
   movb   7(%ebp), %al
Compared to:

Code: Select all

   movzwl   8(%ebp), %edx
   movzbl   12(%ebp), %eax
CodeCat
Member
Member
Posts: 158
Joined: Tue Sep 23, 2008 1:45 pm
Location: Eindhoven, Netherlands

Re: Outb; can you explain why one function works and one doesn't

Post by CodeCat »

In a 32 bit environment all elements on the stack are 32 bits, or 4 bytes in size. No exceptions. You're simply reading the command line arguments from the wrong addresses.
Puffy
Member
Member
Posts: 26
Joined: Mon May 26, 2008 7:00 am

Re: Outb; can you explain why one function works and one doesn't

Post by Puffy »

Edit: Wrote this before the second reply. Cheers guys.

Ok, so if I change my offsets to 8 and 12 it works, but I don't understand why. The function is passed a short (2 bytes) and a char (1 byte), so why do I have to offset by 4 bytes each time?
CodeCat
Member
Member
Posts: 158
Joined: Tue Sep 23, 2008 1:45 pm
Location: Eindhoven, Netherlands

Re: Outb; can you explain why one function works and one doesn't

Post by CodeCat »

4-byte alignment shows up in more places than just the stack, too. If you declare a struct like this

Code: Select all

struct Blah
{
	short one;
	int two;
	char three;
};
Then on most 32 bit platforms, the size of the entire struct will be 12 bytes. What happens is that because the int needs 4 bytes, it automatically aligns it on a 4-byte boundary (this is faster). So it adds 2 more bytes of empty padding after the 2-byte short. The size of the entire struct is also padded up to the next 4 bytes, which adds another 3 empty bytes after the char. So the real struct is laid out like this:

Code: Select all

struct Blah
{
	short one;
	char padding1[2];
	int two;
	char three;
	char padding2[3];
};
The general rule with respect to any kind of value is that its first byte must always be located on an address that is a multiple of its own size. So if you have a struct with 2 shorts it will be 4 bytes and not 8, and 4 chars will also be 4 bytes and not 16. But 2 chars in a struct will also make it 4 bytes, because the size of the struct itself is always a multiple of 4.

To take advantage of this, if you ever use values that are less than 4 bytes in size, you should try to always use them in pairs or quads, so that they fill up the space most efficiently without padding.
Post Reply