llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.05k stars 11.58k forks source link

Bad code generation on i686 w/ inline assembly and -mstackrealign #22442

Closed llvmbot closed 8 years ago

llvmbot commented 9 years ago
Bugzilla Link 22068
Resolution DUPLICATE
Resolved on Nov 03, 2015 17:45
Version trunk
OS Linux
Attachments minimal repro C file
Reporter LLVM Bugzilla Contributor
CC @rnk

Extended Description

I'm trying to compile a Native Client tool (nacl_helper_bootstrap[1]) w/ Clang that make direct syscalls using inline assembly (using the linux-syscall-support[2] library).

The x86_64 version of the tool works, but the i686 version segfaults. I tracked it down to this function, which I've expanded using clang -m32 -E (also attached):

static int my_errno;

void sys_mmap2(void s, size_t l, int p, int f, int d, off_t o) { long res; struct { long a1; long a6; } s = {(long)s, (long)o}; asm volatile( "push %%ebp\n" "push %%ebx\n" "movl 4(%2),%%ebp\n" "movl 0(%2), %%ebx\n" "movl %1,%%eax\n" "int $0x80\n" "pop %%ebx\n" "pop %%ebp" : "=a"(res) : "i"(192), "0"((long)(&s)), "c"((long)(l)), "d"((long)(p)), "S"((long)(f)), "D"((long)(d)) : "esp", "memory"); do { if ((unsigned long)(__res) >= (unsigned long)(-4095)) { my_errno = -(res); res = -1; } return (void*)(__res); } while (0); }

I compile this using clang version 3.6.0 (trunk 223108) and the following commandline:

clang -m32 -mstackrealign -O0 -c test.c -o test.o

And get the following output:

00000000 : 0: 55 push %ebp 1: 89 e5 mov %esp,%ebp 3: 53 push %ebx 4: 57 push %edi 5: 56 push %esi 6: 83 e4 f8 and $0xfffffff8,%esp 9: 83 ec 40 sub $0x40,%esp c: 89 e6 mov %esp,%esi e: 8b 45 1c mov 0x1c(%ebp),%eax 11: 8b 4d 18 mov 0x18(%ebp),%ecx 14: 8b 55 14 mov 0x14(%ebp),%edx 17: 8b 7d 10 mov 0x10(%ebp),%edi 1a: 8b 5d 0c mov 0xc(%ebp),%ebx 1d: 89 46 14 mov %eax,0x14(%esi) 20: 8b 45 08 mov 0x8(%ebp),%eax 23: 89 46 10 mov %eax,0x10(%esi) 26: 8d 46 18 lea 0x18(%esi),%eax 29: 89 46 0c mov %eax,0xc(%esi) 2c: 8b 46 10 mov 0x10(%esi),%eax 2f: 89 46 38 mov %eax,0x38(%esi) 32: 89 5e 34 mov %ebx,0x34(%esi) 35: 89 7e 30 mov %edi,0x30(%esi) 38: 89 56 2c mov %edx,0x2c(%esi) 3b: 89 4e 28 mov %ecx,0x28(%esi) 3e: 8b 4e 14 mov 0x14(%esi),%ecx 41: 89 4e 24 mov %ecx,0x24(%esi) 44: 8b 56 38 mov 0x38(%esi),%edx 47: 89 56 18 mov %edx,0x18(%esi) 4a: 8b 56 24 mov 0x24(%esi),%edx 4d: 89 56 1c mov %edx,0x1c(%esi) 50: 8b 4e 34 mov 0x34(%esi),%ecx 53: 8b 56 30 mov 0x30(%esi),%edx 56: 8b 7e 2c mov 0x2c(%esi),%edi 59: 8b 5e 28 mov 0x28(%esi),%ebx 5c: 8b 46 0c mov 0xc(%esi),%eax 5f: 89 fe mov %edi,%esi 61: 89 df mov %ebx,%edi 63: 55 push %ebp 64: 53 push %ebx 65: 8b 68 04 mov 0x4(%eax),%ebp 68: 8b 18 mov (%eax),%ebx 6a: b8 c0 00 00 00 mov $0xc0,%eax 6f: cd 80 int $0x80 71: 5b pop %ebx 72: 5d pop %ebp 73: 89 46 20 mov %eax,0x20(%esi) 76: 81 7e 20 01 f0 ff ff cmpl $0xfffff001,0x20(%esi) 7d: 0f 82 11 00 00 00 jb 94 <sys_mmap2+0x94> 83: 31 c0 xor %eax,%eax 85: 2b 46 20 sub 0x20(%esi),%eax 88: a3 00 00 00 00 mov %eax,0x0 8d: c7 46 20 ff ff ff ff movl $0xffffffff,0x20(%esi) 94: 8b 46 20 mov 0x20(%esi),%eax 97: 89 46 08 mov %eax,0x8(%esi) 9a: 8b 46 08 mov 0x8(%esi),%eax 9d: 8d 65 f4 lea -0xc(%ebp),%esp a0: 5e pop %esi a1: 5f pop %edi a2: 5b pop %ebx a3: 5d pop %ebp a4: c3 ret

The program crashes at instruction 0x73. This is because %esi is not an address, but actually the flags for the mmap2 syscall. The code generated assumes that %esi is still set to %esp (done at instruction 0xc).

This bug does not occur if I remove -mstackrealign:

... 48: 8b 75 e4 mov -0x1c(%ebp),%esi 4b: 8b 7d e0 mov -0x20(%ebp),%edi 4e: 55 push %ebp 4f: 53 push %ebx 50: 8b 68 04 mov 0x4(%eax),%ebp 53: 8b 18 mov (%eax),%ebx 55: b8 c0 00 00 00 mov $0xc0,%eax 5a: cd 80 int $0x80 5c: 5b pop %ebx 5d: 5d pop %ebp 5e: 89 45 d8 mov %eax,-0x28(%ebp) ...

Nor does it occur when using the default clang on Ubuntu Trusty (Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final)):

... 5d: 8b 74 24 1c mov 0x1c(%esp),%esi 61: 8b 7c 24 18 mov 0x18(%esp),%edi 65: 55 push %ebp 66: 53 push %ebx 67: 8b 68 04 mov 0x4(%eax),%ebp 6a: 8b 18 mov (%eax),%ebx 6c: b8 c0 00 00 00 mov $0xc0,%eax 71: cd 80 int $0x80 73: 5b pop %ebx 74: 5d pop %ebp 75: 89 44 24 10 mov %eax,0x10(%esp) ...

This bug still occurs with optimization turned on (I tried -O2), but not in this simple example.

[1]https://code.google.com/p/chromium/codesearch#chromium/src/native_client/src/trusted/service_runtime/linux/nacl_bootstrap.c [2]https://code.google.com/p/linux-syscall-support/

rnk commented 9 years ago

This is a known issue with our stack realignment that happens with rbx on x64.

I ran into and tried to make us fatal error in these situations: http://reviews.llvm.org/D1317

I'm going to dupe this against llvm/llvm-project#17204 , since it's older and basically the same problem. The core issue is that aligned stack space with a moving SP requires three pointers to the stack:

Keeping ebp where it is also keeps a reference to the return address, which is good for frame pointer based unwinders.

This bug has been marked as a duplicate of bug llvm/llvm-project#17204