-1

If I am correct, an assembly language uses the program stack to store data.

Is it correct that the program stack is partitioned to frames, each of which is for a call to a procedure? So there is no part of the program stack, which is not associated with a procedure?

If an assembly program doesn't call any procedure, is it by default a procedure itself? Does it occupy a frame in the program stack?

Thanks.

3

The default stack mechanism in assembly language is limited to the pushing and poping of the return address when you call a subbroutine. By default, there is no additional things stored on the stack when you make a CALL

At assembly level, the closest thing to a local variable is the CPU register. The problem with a CALL, is that the called subroutine might almost certainly change registers, since there are only a few of them. So a common assembly technique was to push the registers on the stack before you make the call, and pop them brom the stack when the call returns.

But this is a very limited approach, that is not sufficient for modern high-level languages making extensive use of calls and have usually many more local variables than there are registers. So the trick is then to use stack-frames, playing with the stack register to reserver extra place for locals, and using indirect memory acess via the stack register to access the locals.

Compilers generate such stack frame management for you. If you start with assembly from the scratch, you have to do it yourself.

By the way, in assembly there is no default procedure. The call of a main() function is a modern way to launch programmes, that is performed by the operating system. I think it is inherited from unix. Pure assembly, without OS, starts to execute code with an empty stack at a fixed address. That's what happens when you boot a computer.

3

"Stack frame" is a concept, or a convention. It is created to help programmers create programs (whether from assembly language or from higher-level languages) that can work together correctly.

One crucial requirement of getting pieces of code to work together is that the caller and the callee must agree on how data is passed via the stack and/or via CPU registers.


As an assembly programmer, one is not bound by existing conventions for using the stack space, other than a few basic requirements imposed by the CPU instruction set architecture (CPU ISA) and the operating system (the OS).

In particular, if your assembly program doesn't involve any function calls, you do not need to define or follow any convention. Similarly, if your assembly program only makes function calls and jumps within code that is all written by you, you are free to set up your own conventions for using the stack space.

You are, therefore, free to redefine the meaning and the convention of "stack frame", with respect to your assembly program.


However, if you are a student who want to learn about following the conventions of the computing world, any textbook that teaches you assembly program will definitely contain chapters that teach you a particular convention for the stack frame. In general, a software program should follow such convention in order to be useful.


The rest of this answer makes the assumption that the assembly program is compiled ("assembled") into an executable ("binary") and then executed with the help of the operating system.


The reader shall learn about the roles, the basic requirements, and the basic operations of the application loader.


The loader is responsible for setting up the initial environment of any application.

The "stack" is a range of memory pages (a large consecutive swath of memory address) that the loader has allocated on behalf of the application at the beginning. The stack space is not pre-partitioned. When the application is just started, it is just a contiguous space.

Depending on the convention of the CPU instruction set architecture, there are some rules for using the stack.

For example, on the x86 CPU architecture, the stack pointer is initialized with a high address value within the stack space; every "push" operation causes the stack pointer to move toward a lower address value; every "pop" operation restores what has been "pushed" earlier.

Some OSes impose requirements on how the application can use the stack. Some don't.

The amount of stack space that will be consumed during a function's execution will vary depending on the needs of the function. For example, a function that needs to remember five local variables of word-size will need more stack space than a function that only needs to remember three.

A function that is recursive may need a potentially unbounded amount of stack space. Each time the function calls itself, it will consume some stack space. The operating system and/or the CPU architecture implements some mechanisms that detect the exhaustion of stack space, in order to prevent or stop incorrect execution.

2

Most running programs push and pop things on the stack during function invocation and return.

Usually a high level language program will provide a user-defined main, which is called by some language or runtime startup code, which is the first code run in the program.

We can write a C-style program in assembly language by providing a main function — this will be called by the startup code as a (relatively) normal function.  We don't have to call any other functions, and, main is a function that gets parameters and returns a value like other functions.

Using assembly language (and proper linker options), we can substitute our own code for the standard runtime startup, and thus, our code will execute, as the first code in the process, without assistance from a language runtime startup.  Runtime startup code may (but doesn't have to) call functions, but itself probably doesn't qualify as a function — for example, it has no where to return to, so the proper way to exit this kind of code is to make a system call to exit the process rather than to return to its caller in the way of a normal function.

In either case, the operating system (these days) will have created an initial thread with an initial stack, which probably has some arguments on it — in this case program arguments, e.g. command line arguments packaged in a way accessible to (a language runtime) startup code (but not necessarily as normal function arguments), and eventually these program arguments are (normally) offered to main as regular function arguments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.