Using stack for arguments

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
twtty
Posts: 8
Joined: Wed Feb 10, 2016 6:30 pm

Using stack for arguments

Post by twtty »

I do not feel entirely sure as to whether this fits best here or under the General Programming. Should you feel it fits best under there, feel free to move this post! It is somewhat OS related as it is using BIOS interrupts and its registers for storing values.

I have been attempting to use a stack for variable transportation to a function. The code is compiled using NASM, which probably seems rather obvious to most. I have a stack set up like this:

Code: Select all

cli
mov ax, 0x0000
mov ss, ax
mov sp, 0xffff
sti
The variables I push to the stack are the head, track and sector used when loading from a disk. I push them like this:

Code: Select all

push 0			; Head
push 0			; Track
push 2			; Sector
These are supposed to be loaded into CH (track number), CL (sector number) and DH (head number). I have tried various different methods to go about doing so. As my understanding of NASM is somewhat limited, it would be nice if somebody could explain to me the proper way of loading the correct values into the correct registers.

Here is what I am trying to achieve, but loading them from the stack rather than just hard coding in the values:

Code: Select all

mov cl, 2		; Sector
mov ch, 0		; Track
mov dh, 0		; Head
Disk loading otherwise works fine, thanks to everybody who answered my previous post! :)

Any information you can give explaining the various aspects of using the stack for arguments would be wonderful. When I began trying to get using the stack for arguments to work, I thought it was as simple as popping off the argument into any of the registers. How come for example you cannot pop into the CL, CH and DH registers? Also, what is the proper way to do this?

Thank you!

Best regards,

Red
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Using stack for arguments

Post by iansjack »

1. Don't set your stack pointer to an odd address. It must be 16-bit aligned (i.e. an even address.). Set it to 0 instead of 0xffff.

2. You can only pop into 16-, 32-, or 64-bit registers, not the 8-bit ones. How come? That's just the way things are.

3. The proper way is just to load the values into the registers. What's the point of this additional push/pop? If you really want to do this for some reason you will have to push/pop CX and DX.
twtty
Posts: 8
Joined: Wed Feb 10, 2016 6:30 pm

Re: Using stack for arguments

Post by twtty »

Is it not so that the stack builds downwards rather than upwards? By setting the stack pointer to zero, would it not stop working?

The point in "additional push / pops" is that the registers are cleared during the duration of a function call, I need some way of retrieving the values even after the registers have been reset. Currently what I have attempted:

Code: Select all

pop ax
mov cl, al		; Attempting to put popped value in CL

; Push back onto stack
push ax
This however, does not work. How come?
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Using stack for arguments

Post by iansjack »

twtty wrote:Is it not so that the stack builds downwards rather than upwards?
That is correct. The instruction PUSH AX

1. Subtracts 2 from the value in SP.
2. Stores the word in AX in the memory location now pointed to by SP.

If SP starts out as 0 this will result in a new SP value of 0xFFFE with the contents of AX stored in the memory location SS:0xFFFE.
This however, does not work. How come?
"Does not work" is a little vague. Exactly what doesn't work?

I think you should try running snippets of code in a debugger, single-stepping through the code and inspecting the values in registers and memory at each step. Then you will get a grasp of what is going on.

As far as this question is concerned, that's it from me. This forum is not really intended to be a primer on assembler programming. But a Google search will reveal several excellent tutorial and books that will teach you the basics and beyond.
twtty
Posts: 8
Joined: Wed Feb 10, 2016 6:30 pm

Re: Using stack for arguments

Post by twtty »

As far as this question is concerned, that's it from me. This forum is not really intended to be a primer on assembler programming. But a Google search will reveal several excellent tutorial and books that will teach you the basics and beyond.
Thank you for your kind help! After some fiddling with it I managed to get it to work. I do have one final question thought: how come the arguments I am sending to function are located two bytes into the stack? That is, how come I need to subtract the SP by two in order to be at where the arguments are stored? Is it the function call itself that is also stored in the stack, or is it something else?

Here is what I do:

Code: Select all

add sp, 2
pop ax		; Correct value popped into AX (previously pushed argument)
mov cl, al
push ax
sub sp, 2
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: Using stack for arguments

Post by SpyderTL »

Yes, calling a subroutine/function in the same segment is called a "near call", and it pushes the 2 byte return address onto the stack. The return from near call instruction simply pops the top 2 bytes and puts them in the IP register.

If you call a function in a different segment, that is a far call. In this case, the return address and the return segment are pushed onto the stack.

Edit: Also, there is no reason to push AX back onto the stack. You can simply just subtract 2 from SP.

Or better yet, don't modify SP at all, and use stack pointer offsets to read the incoming values.

Code: Select all

mov ax, [sp+2]
You can even pass the amount of memory passed to the function to the RET instruction, which will pop the top 2 bytes to IP, and then add the specified value to SP, effectively "removing" those values from the stack.

Code: Select all

ret 2
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Using stack for arguments

Post by iansjack »

SpyderTL wrote:Or better yet, don't modify SP at all, and use stack pointer offsets to read the incoming values.
Even better is the 64-bit ABI which passes parameters to function calls in registers (within reason) rather than using the stack. Of course, this relies upon the CPU having a reasonable number of registers which is why it wasn't used in earlier iterations of the processor.
twtty
Posts: 8
Joined: Wed Feb 10, 2016 6:30 pm

Re: Using stack for arguments

Post by twtty »

Or better yet, don't modify SP at all, and use stack pointer offsets to read the incoming values.
SP however cannot be used in this, correct? Rather BX or BP, SI or DI has to be used for addressing as such.
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Using stack for arguments

Post by onlyonemac »

SpyderTL wrote:Edit: Also, there is no reason to push AX back onto the stack. You can simply just subtract 2 from SP.

Or better yet, don't modify SP at all, and use stack pointer offsets to read the incoming values.
I tend to find that using push/pop to work with the stack rather than fiddling with the stack pointer makes for cleaner code (as, for example, one can ignore the size of the values on the stack and the code better reflects its function), although I believe that working with the stack pointer directly might make the code faster and that's probably why a lot of compilers do that.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Using stack for arguments

Post by iansjack »

I suspect that compilers work that way because that is how they have to access local variables and it makes sense to treat parameters in the same way. Particularly as the local variables are allocated lower in the stack than the function parameters.
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: Using stack for arguments

Post by onlyonemac »

iansjack wrote:I suspect that compilers work that way because that is how they have to access local variables and it makes sense to treat parameters in the same way. Particularly as the local variables are allocated lower in the stack than the function parameters.
True, it didn't occur to me that local variables are stored on the stack but I guess that's probably why, because then local variables and parameters can be treated the same way (i.e. determine offset of variable from stack pointer, then use that offset everywhere that you want to access that variable) without caring about how they got onto the stack (other than is needed to calculate the offset).
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: Using stack for arguments

Post by SpyderTL »

twtty wrote:
Or better yet, don't modify SP at all, and use stack pointer offsets to read the incoming values.
SP however cannot be used in this, correct? Rather BX or BP, SI or DI has to be used for addressing as such.
You can do [SP+/-] offsets in 32-bit mode. I'll have to look up whether you can do it in 16-bit mode. If NASM complains, then you are probably right.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Post Reply