7

Recently I rewrote some libc functions in assembly and for some of them (the one that didn't need any call or syscall instructions, like strlen), I discarded the prologue and epilogue because my tests didn't failed without it (maybe they were not complex enough). During peer review, someone told me it was bad practice to discard them, but couldn't explain me why.

So, am I running into problems when I call asm functions that don't have the prologue/epilogue combination?

Is it a good practice to add it even when no additionnal space is needed on the stack?

If mandatory for some reasons, why doesn't the assembler (I used nasm) take care of it?

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
shorty_ponton
  • 454
  • 4
  • 14
  • 3
    In optimized production code, skip the prologue/epilogue if not needed. However, for debugging or profiling it might be useful to have a clean stack frame, many debuggers rely on that. – Ctx Feb 13 '17 at 15:54
  • `syscall` isn't special and doesn't make a function non-leaf. A syscall uses the kernel stack, not the user-space stack. – Peter Cordes Mar 16 '20 at 09:32

2 Answers2

5

If you do not set up a proper stack frame, it can be hard for a debugger to know what function you are in right now. On ELF-targets, you have to manually provide CFI data (cf. this article) if you do not explicitly set up a stack frame. Without CFI data, stack unwinding doesn't work and the debugger might not be able to find out what function you are in. Unless you want to manually add CFI data (which is somewhat tedious and easy to get wrong), I recommend you to accept the minor performance loss and just set up a full stack frame.

fuz
  • 88,405
  • 25
  • 200
  • 352
  • Ok I get it thks. I'll try to do some debug with and without new stack frame in my functions to get a better hang on all this – shorty_ponton Feb 13 '17 at 16:21
  • @fuz: even for a leaf function? I've never seen GDB have a problem; it just looks for the most recent global symbol before the current RIP which has nothing to do with contents of other registers or stack memory. The OP seems to only be talking about leaf functions, not backtracing or `frame 2` through frame-pointer-omitting parent functions. – Peter Cordes Mar 16 '20 at 09:34
  • @PeterCordes I suppose the debugger should be fine for leaf functions. I'm not too sure either. – fuz Mar 16 '20 at 09:56
  • 1
    I'd say I *am* pretty sure it's fine to omit frame pointers in hand-written asm for leaf functions. (If you don't care about breaking backtraces or Windows SEH or whatever else might need to unwind the stack). If it's just for manual debugging of the current function, I've never seen GDB be unable to find the *current* location. That's why I didn't upvote this answer. (I didn't downvote, but I pretty liberally upvote answers that I think are right and at least somewhat useful.) – Peter Cordes Mar 16 '20 at 10:05
2

Are the prologue and epilogue mandatory when writing assembly functions?

For pure assembly you don't even need to have "functions" - e.g. you can have a piece of code with multiple different entry points and a single "ret" (which is equivalent to what you might end up with after a decent compiler does "tail call" optimizations).

For writing functions that are compatible with someone else's calling conventions; you have to comply with someone else's calling conventions. If those calling conventions say that (e.g.) some registers must be preserved by callee, then the callee has to preserve those registers (by saving in prologue and loading in epilogue) and if it doesn't you can end up with unexpected data corruption (because compiler expected a value to remain unchanged but..).

Note that for 80x86, none of the calling conventions require a stack frame (as EBP or RBP) - that's just historical memorabilia resulting from the poor design of ancient debuggers, and ceased being sane when debuggers switched to better techniques about 20 years ago.

If mandatory for some reasons, why doesn't the assembler (I used nasm) take care of it?

Assemblers typically have no idea which calling convention (if any) you're trying to comply with.

Brendan
  • 35,656
  • 2
  • 39
  • 66