Click here to Skip to main content
15,881,172 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Here's a short program....
int main()
{
	_asm
	{
		push al;
		pop al;
		pop al;
	};
    return 0;
}

which doesn't do much but it works. But I don't think it should, as I push 'al' onto the stack then try and pull it off twice, hence knackered stack.

It seems that the push is actually moving the stack pointer by 4 bytes, whereas the pop is only moving it back by 2, yet the register is supposed to be a single byte, the lower half of a 16bit thing. What's going on?

What I have tried:

Well, I tried thinking about it in my head for a bit, but it didn't help.
Posted
Updated 10-Apr-19 4:40am
Comments
Dave Kreskowiak 10-Apr-19 11:30am    
Excellent question to get people thinking.

I was about to chime in with a "check the .ASM log of your compile or the disassembler window to see what it's really doing" when I found you made that very comment 10 minutes ago.
[no name] 10-Apr-19 11:47am    
1

Quote:
It seems that the push is actually moving the stack pointer by 4 bytes, whereas the pop is only moving it back by 2, yet the register is supposed to be a single byte, the lower half of a 16bit thing. What's going on?

al register is 1 byte, so push and pop are moving stack pointer 1 byte.
By design, stack pointer move accordingly with size of register you selected. Your duty is to make all stack operations consistent.

Use debugger to be able to see what happen exactly.
Debugger - Wikipedia, the free encyclopedia[^]

Mastering Debugging in Visual Studio 2010 - A Beginner's Guide[^]
Basic Debugging with Visual Studio 2010 - YouTube[^]
 
Share this answer
 
Comments
Rob Philpott 10-Apr-19 10:54am    
I agree, but that's not what I'm seeing (in the debugger).

For instance for push/pop EAX here are the values of ESP before the push, then before the pop and after the pop:

0x39f7b0
0x39f7ac
0x39f7b0

Exactly what you expect, 4 byte movement each way for a 4 byte register. For push/pop AX I got:

0x3ffc60
0x3ffc5e
0x3ffc60

Again, exactly as you'd expect with a 2 byte movement for a 2 byte register. But when I do it for just AL, I get this:

0x3ef8c8
0x3ef8c4
0x3ef8c6

So a movement of 4 bytes for the push, and 2 bytes for the pop, after which Visual Studio gets all upset because the stack is wrong.
Patrice T 10-Apr-19 11:06am    
Then is it can't handle this perfectly legal code:
	_asm	{		push al;		push bl;		pop cx;	};

Bug in cpu or VS ?
Rob Philpott 10-Apr-19 11:15am    
The assembler I think. It just occurred to me to check the disassembly window, and it shows this:

push al;
000C16A0 push eax
pop al;
000C16A3 pop ax

so push AL => push EAX, and pop AL => pop AX. This is VS2015 C++ in an asm block.
Patrice T 10-Apr-19 11:26am    
Then you know the reason :)
[no name] 10-Apr-19 11:47am    
1
Popping the value off an empty stack doesn't necessarily do anything "bad", it just retrieves a value at an address, and decrements the pointer. It's only if that address is outside the memory space for the process that you will get an error. In theory, you could get a problem from the "return 0" as it should be using the stack to fetch the exit address and you have removed that from the stack, but the chances are that your compiler doesn't use the machine code "return" but terminates the process via a system call instead - I've seen it done both ways depending on the compiler writers preferences.

As for the size, when you add or remove any item from the stack in machine code, you use the same amount of space - a machine word, which is likely to be 16, 32, or 64 bits. If it didn't, then the stack would end up at odd addresses which is a bad idea for technical reasons.
I'm surprised that "push al" worked at all - the machine code it generates will almost certainly be "push ax" to avoid odd addresses.
 
Share this answer
 
Comments
Rob Philpott 10-Apr-19 10:22am    
Yes, it's mighty odd if you ask me. If I push then pop EAX, everything is fine. If I push then pop AX, also everything is fine, but when you go down to AL, the push and the pop move the stack pointer by different amounts, neither what I'd expect. And I don't think it is down to word alignment either.

I'm mucking around here, the only assembly language programming I've done in earnest is on ARM where the CPU is a well organized thing of beauty, not some transistor equivalent of a teenager's bedroom with X86 daubed on the door.

It's the compiler I feel sorry for...
Patrice T 10-Apr-19 10:42am    
"I'm surprised that "push al" worked at all - the machine code it generates will almost certainly be "push ax" to avoid odd addresses."
No, this is legacy compatibility, processor have no choice, even if it involve extra work to handle misaligned data.
[no name] 10-Apr-19 11:47am    
1

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900