Stack and assembler

Programming, for all ages and all languages.
Post Reply
User avatar
VolTeK
Member
Member
Posts: 815
Joined: Sat Nov 15, 2008 2:37 pm
Location: The Fire Nation

Stack and assembler

Post by VolTeK »

For a while i had been playing with having my variables put onto the stack, Since i'm multitasking in real mode, very soon ill need my core components to run on the stack since their values are in one place rather then one per program.

Question is, do you use the stack for variables in assembler? What calling convention do you use? Do you think its useless to, and why?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Stack and assembler

Post by bluemoon »

Multitasking has little to do with variable scope. Are you sure you are not confused?
Multi-threading however, usually make use of local variable, which depends on ABI, can be placed on stack in most implementation.
User avatar
VolTeK
Member
Member
Posts: 815
Joined: Sat Nov 15, 2008 2:37 pm
Location: The Fire Nation

Re: Stack and assembler

Post by VolTeK »

Not confused, you may have misread or don't know what i'm trying to get at.

During a task switch (on my task switcher) in real mode, the stack address is saved.

On the stack, are the programs variables. (Not its global variables)

My system core is called by many programs running at once, since the variables i have now are global (physically part of the program) their content can be modified many times a second, by multiple programs calling just the one. There is many instances of the core function (open in every process that called it) but they all act off one piece of code, one set of variables but a stack for each program.

If the core function puts its variables on the stack, and there is multiple stacks (one per program) there is multiple versions of variables, off one set of code.

Understand what i mean now?
User avatar
iansjack
Member
Member
Posts: 4687
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Stack and assembler

Post by iansjack »

There should only be one copy of a true global variable (otherwise it wouldn't be global). An example would be currentProcess or nextFreePhysicalPage. All programs need to see the same version and value of this when they access it (via the kernel). These would be stored in fixed locations in kernel memory. Some may be more indirectly stored, as part of a linked list for example, but still not on the stack.

Local variables may have the same name, but different values, for different processes. Examples would be currentDirectory or nextFreeMemoryOnHeap. These could be stored in memory that is unique to the process; in a reasonably sophisticated OS processes won't be able to see the memory belonging to other processes. Alternatively, they may be stored as part of the process structure in the process table and only accessed via the kernel.

Some variables are global to a particular process, but may not exist in other processes; for example currentLineNumber in an editor. These are best stored in the private memory of the process. Several instances of the variable may exist at the same time in the system, but only one will exist for a particular process.

Variables stored on the stack are only really useful as variables local to a particular function. Else it becomes difficult to keep track of their position. Storage in a fixed memory location is not appropriate here because functions may be called recursively or, in a multi-threaded system, different instances of the function may be active at the same time. Thus there is a need to allow several instances of the same variable within a process.
User avatar
VolTeK
Member
Member
Posts: 815
Joined: Sat Nov 15, 2008 2:37 pm
Location: The Fire Nation

Re: Stack and assembler

Post by VolTeK »

VolTeK wrote:Question is, do you use the stack for variables in assembler? What calling convention do you use? Do you think its useless to, and why?
iansjack wrote:There should only be one copy of a true global variable (otherwise it wouldn't be global). An example would be currentProcess or nextFreePhysicalPage. All programs need to see the same version and value of this when they access it (via the kernel). These would be stored in fixed locations in kernel memory. Some may be more indirectly stored, as part of a linked list for example, but still not on the stack.

Local variables may have the same name, but different values, for different processes. Examples would be currentDirectory or nextFreeMemoryOnHeap. These could be stored in memory that is unique to the process; in a reasonably sophisticated OS processes won't be able to see the memory belonging to other processes. Alternatively, they may be stored as part of the process structure in the process table and only accessed via the kernel.

Some variables are global to a particular process, but may not exist in other processes; for example currentLineNumber in an editor. These are best stored in the private memory of the process. Several instances of the variable may exist at the same time in the system, but only one will exist for a particular process.

Variables stored on the stack are only really useful as variables local to a particular function. Else it becomes difficult to keep track of their position. Storage in a fixed memory location is not appropriate here because functions may be called recursively or, in a multi-threaded system, different instances of the function may be active at the same time. Thus there is a need to allow several instances of the same variable within a process.

I don't give a $hit.
VolTeK wrote:My system core is called by many programs running at once, since the variables i have now are global (physically part of the program) their content can be modified many times a second, by multiple programs calling just the one. There is many instances of the core function (open in every process that called it) but they all act off one piece of code, one set of variables but a stack for each program.

If the core function puts its variables on the stack, and there is multiple stacks (one per program) there is multiple versions of variables, off one set of code.

That is how it works, in a nut shell. That is how my system will use it. I don't care about the science behind it, because i already went over it. Quit wasting your time and answer This
VolTeK wrote:Question is, do you use the stack for variables in assembler? What calling convention do you use? Do you think its useless to, and why?

I really don't know how much more straight forward i need to be with you kids.
User avatar
Kazinsal
Member
Member
Posts: 559
Joined: Wed Jul 13, 2011 7:38 pm
Libera.chat IRC: Kazinsal
Location: Vancouver
Contact:

Re: Stack and assembler

Post by Kazinsal »

VolTeK wrote:I don't give a $hit.
That is the best way to get help from people, really. Swearing at them when they try to help you always works. /s
VolTeK wrote:I really don't know how much more straight forward i need to be with you kids.
If you don't like how us "kids" handle it here (judging from your attitude I'd wager you're fifteen or so) then find someplace else. Try StackExchange. Maybe they'll cater to someone more of your brilliance and maturity. :roll:
User avatar
iansjack
Member
Member
Posts: 4687
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Stack and assembler

Post by iansjack »

I guess I have better ways of spending my time than trying to help the terminally stupid. Just because you don't understand the first thing about assembler programming or OS development is no reason to be rude.

One of us knows what he is doing, the other clearly has no idea. Who's the one asking the beginner's questions? Go figure. :D
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Stack and assembler

Post by bluemoon »

I too lost interest in figure out what exactly the OP is asking; on the other hand I don't like flame. So let's keep it unresolved.
User avatar
Jezze
Member
Member
Posts: 395
Joined: Thu Jul 26, 2007 1:53 am
Libera.chat IRC: jfu
Contact:

Re: Stack and assembler

Post by Jezze »

Just to give you an idea about how obvious you are.
For a while i had been playing with having my variables put onto the stack,
What else could you possibly use the stack for?
Since i'm multitasking in real mode, very soon ill need my core components to run on the stack since their values are in one place rather then one per program.
Let me ponder that for a while... "my core components to run on the stack"... wtf does that mean? What are core components? The kernel(s)? And why is it running on the stack? It would make sense if it used a stack to store variables but not run on the stack. Makes no sense.
Question is, do you use the stack for variables in assembler? What calling convention do you use? Do you think its useless to, and why?
Question should rather be: Do you use the stack and if you use the stack what calling convention do you use? If you think the stack is useless please explain why.

Answer: Yes I use the stack and I use the c calling convention. No, the stack is not useless.
Fudge - Simplicity, clarity and speed.
http://github.com/Jezze/fudge/
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Stack and assembler

Post by Brendan »

Hi,
VolTeK wrote:Question is, do you use the stack for variables in assembler?
Usually, no - I use registers for temporary/local variables, and either global variables or allocated/heap for "less temporary" purposes. I do use the stack for temporary/local variables if I run out of registers, but most routines are small enough to be maintainable and therefore are small enough not to need the stack for temporary/local variables.

I do use the stack for saving/restoring "trashed" registers though.
VolTeK wrote:What calling convention do you use?
Mine.

For things called from external code (e.g. kernel API, etc); parameters are passed in registers (in order: eax for first parameter, ebx for second, etc). Returned values are returned in registers too (in the same "eax for first, ..." order) where "eax" is almost always used for status (0 = success, nonzero = some error code). Any register that is not used to return values is guaranteed to contain the same value it did before the routine was called (e.g. if a register is modified but not used to return a value, I'll push it on the stack at the start and then pop it before returning). For example:

Code: Select all

;Add three 32-bit unsigned values
;
;Input
; eax = first value
; ebx = second value
; ecx = third value
;
;Output
; eax = status (0 = ok, 1 = overflowed)
; ebx = result
; All other registers unchanged

addThreeValues:
    add ebx,eax
    jc .overflowed
    add ebx,ecx
    jc .overflowed
    xor eax,eax
    ret

.overflowed:
    mov eax,1
    ret


For internal routines (routines that are only called from something else in the same piece of code) the calling convention is loosely similar; but different registers might be used for convenience (e.g. if ESI happens to be more convenient for most callers, then I'll use ESI instead of EAX for the first parameter) and status might be returned in a flag (e.g. carry flag) or no status might be returned at all. Also, if it happens to be more convenient, I might not preserve the contents of some trashed registers (and document it instead). For example:

Code: Select all

;Add three 32-bit unsigned values
;
;Input
; eax = first value
; ecx = second value
; esi = third value
;
;Output
; carry = set if overflowed
; esi = result
;
;Trashed
; ecx

addThreeValues:
    add ecx,eax
    jc .done
    add esi,ecx
.done:
    ret



Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
rdos
Member
Member
Posts: 3279
Joined: Wed Oct 01, 2008 1:55 pm

Re: Stack and assembler

Post by rdos »

To use local variables in assembler, you can do it exactly the same way as the C compiler does it.

Here is a sample of how to do it:

Code: Select all


curr_start  EQU -8
curr_size   EQU -6
curr_x      EQU -4
curr_y      EQU -2

set_native      Proc far
    push ds
    push es
    pusha
    mov bp,sp
    sub sp,10
;
    mov [bp].curr_x,1            ; set local variable curr_x to 1
    mov [bp].curr_y,10          ; set local variable curr_y to 10
;
    add sp,10
    popa
    pop es
    pop ds
    ret
set_native      Endp

Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: Stack and assembler

Post by Nable »

Fasm macroses looks much less perverted than manual definition of stack offsets (although, offsets left you more optimization freedom) :

Code: Select all

; VOID ShowErrorMessage(HWND hWnd,DWORD dwError);

proc ShowErrorMessage hWnd,dwError
  local lpBuffer:DWORD
        lea     eax,[lpBuffer]
        invoke  FormatMessage,FORMAT_MESSAGE_ALLOCATE_BUFFER+FORMAT_MESSAGE_FROM_SYSTEM,0,[dwError],LANG_NEUTRAL,eax,0,0
        invoke  MessageBox,[hWnd],[lpBuffer],NULL,MB_ICONERROR+MB_OK
        invoke  LocalFree,[lpBuffer]
        ret
endp
see include/macro/proc{32,64}.inc from Fasm package.
Tosi
Member
Member
Posts: 255
Joined: Tue Jun 15, 2010 9:27 am
Location: Flyover State, United States
Contact:

Re: Stack and assembler

Post by Tosi »

I use the stack as much as possible for local variables because it's faster and makes smaller code. You also don't waste space if you want to, say, align your variable on some boundary (such as requiring dqword/16-byte alignment for faster SSE moves), and it's easy to cleanup once you're done.
This is true in both assembly and C, but more so in C because it gives the compiler more chance to alias registers, and the compiler doesn't have to worry about the variable once it's out of scope.

The manuals at http://www.agner.org/optimize/#manuals are pretty good, and they even cover the newer x86 instructions. The section you need to read is in the x86 subroutine optimization manual, section 4.2 Data Storage. I would copy the relevant text but I don't want to violate the licensing.

Essentially, using stack variables allows for more efficient use of the cache. Even if you're in real mode, if your code is running on a new processor the cache is probably enabled unless you explicitly disabled it. It also makes your code and data smaller, which is always good for real mode.

Global variables do have their place, however. If you need persistent storage of data that will exist throughout the lifetime of your program, then global variables are the way to go.

As for calling conventions, I personally prefer STDCALL, although the Microsoft name-mangling gets annoying. I still use CCALL for variadic functions though I could hack up an STDCALL snprintf if I needed to I guess. I don't use frame pointers unless I have a ton of local variables or I'm debugging and want to have a more reliable stack trace. I never liked fastcall and parameter passing in registers. If speed is that important, then I just inline the function, or if the function is too big, find a way to move it out of an inner loop, unroll the loop some, or journey to the Dark Planes to find a Blessed Scroll of Deep Wizardry Optimization.

The rest of your original post didn't make any sense, and I stopped reading the rest after I saw smoke.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Stack and assembler

Post by bluemoon »

Tosi wrote:I never liked fastcall and parameter passing in registers.
I love it after I tried the x86-64 ABI, I mean, when you have a lot of registers, some delicate for input and some meant to be trashed, you can totally(or greatly) avoid stack for local variables to avoid cache pollution; the result is, memory are dedicated for useful data and call/ret.
Antti
Member
Member
Posts: 923
Joined: Thu Jul 05, 2012 5:12 am
Location: Finland

Re: Stack and assembler

Post by Antti »

When I write assembly routines, I do not use stack very much. Only for pushs and pops. At the beginning, I tried to maintain "x86-64 ABI 16-byte stack alignment." I gave up and now I use only "native 8-byte alignment" in the kernel. SSE instructions are not used.

I wrote my UEFI loader in assembly and I used Microsoft x64 calling convention there. I did not like the "32 bytes shadow space" requirement.
Post Reply