Langmuir, Ben
2013-May-22 18:11 UTC
[LLVMdev] x86 frame pointer and __builtin_setjmp/__builtin_longjmp
Hi, I'm trying to understand how __builtin_setjmp/longjmp are supposed to interact with the frame pointer on x86_64. In particular, what is the expected behavior when the compiler chooses not to use rsp or rbp to address local variables? When built with Clang, the following program will segfault, but it is fine when built with GCC. The target is x86_64 linux. int main(int argc, char *argv[]) { void *buf[20]; __attribute__((__aligned__(64))) char q; // realign the stack char *p = __builtin_alloca(argc); // dynamic alloca if (__builtin_setjmp(buf)) { *p = 'p'; q = 'q'; return 0; } asm("movq $0, %rbx"); __builtin_longjmp(buf, 1); } LLVM is choosing to use rbx as a base pointer to access p and q, but during builtin_setjmp, rbx is not saved; when the longjmp is executed rbx may have a garbage value. GCC on the other hand, is using rbp, which is saved in the jump buffer. Is this a bug in LLVM, or am I using __builtin_setjmp/longjmp incorrectly? Note: I'm explicitly clobbering rbx, but the compiler can clobber it on its own if __builtin_longjmp is called from another function. Ben -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20130522/a6b7cee4/attachment.html>
Hal Finkel
2013-May-22 18:34 UTC
[LLVMdev] [cfe-dev] x86 frame pointer and __builtin_setjmp/__builtin_longjmp
----- Original Message -----> > > > > Hi, > > > > I’m trying to understand how __builtin_setjmp/longjmp are supposed to > interact with the frame pointer on x86_64. In particular, what is > the expected behavior when the compiler chooses not to use rsp or > rbp to address local variables? > > > > When built with Clang, the following program will segfault, but it is > fine when built with GCC. The target is x86_64 linux. > > > > int main(int argc, char *argv[]) { > > void *buf[20]; > > > > __attribute__((__aligned__(64))) char q; // realign the stack > > char *p = __builtin_alloca(argc); // dynamic alloca > > > > if (__builtin_setjmp(buf)) { > > *p = 'p'; > > q = 'q'; > > return 0; > > } > > > > asm("movq $0, %rbx"); > > __builtin_longjmp(buf, 1); > > } > > > > LLVM is choosing to use rbx as a base pointer to access p and q, but > during builtin_setjmp, rbx is not saved; when the longjmp is > executed rbx may have a garbage value. GCC on the other hand, is > using rbp, which is saved in the jump buffer. Is this a bug in LLVM, > or am I using __builtin_setjmp/longjmp incorrectly?IMHO, this is an LLVM bug. The SjLj lowing code should save and restore the base pointer (unless stack realignment is disabled, etc.) whenever the base pointer might be in use. This also highlights the odd design of this feature, which splits the implementation between Clang and the target lowering code. Specifically, I mean that Clang generates intrinsics to save the frame pointer, etc. into the buffer, and this is part of the protocol that the lowering code needs to understand. Can anyone explain the rationale for this split-responsibility design? -Hal> > > > Note: I’m explicitly clobbering rbx, but the compiler can clobber it > on its own if __builtin_longjmp is called from another function. > > > > Ben > _______________________________________________ > cfe-dev mailing list > cfe-dev at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev >