Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improper instructions produced on i686-unknown-linux-gnu #18146

Closed
alexchandel opened this issue Oct 18, 2014 · 11 comments
Closed

Improper instructions produced on i686-unknown-linux-gnu #18146

alexchandel opened this issue Oct 18, 2014 · 11 comments
Labels
A-codegen Area: Code generation

Comments

@alexchandel
Copy link

When cross-compiling a minimal no_std/no_main/no_stack_check program for i686-unknown-linux-gnu on OS X 10.10, rustc inserts two anomalous instructions during machine code generation. Notice the call/pop eax just after .Ltmp2.

From assembly:

ain:
    .cfi_startproc
    pushl   %ebx
.Ltmp0:
    .cfi_def_cfa_offset 8
    subl    $24, %esp
.Ltmp1:
    .cfi_def_cfa_offset 32
.Ltmp2:
    .cfi_offset %ebx, -8
    calll   .L0$pb
.L0$pb:
    popl    %eax
.Ltmp3:
    addl    $_GLOBAL_OFFSET_TABLE_+(.Ltmp3-.L0$pb), %eax
...

From disassembly:

Disassembly of section .text:Disassembly of section .text.main:
main:
       0:   53                                              pushl   %ebx
       1:   83 ec 18                                        subl    $24, %esp
       4:   e8 00 00 00 00                                  calll   0
       9:   58                                              popl    %eax
       a:   81 c0 03 00 00 00                               addl    $3, %eax
...

Popping the former frame pointer would seem to destroy the stack frame. Actually what is depicted above just pops an IP; however it does destroy the stack later. Note that it is never re-pushed later in the function.

Now, this is does not happen when rustc instead emits LLVM IR that is separately compiled with clang. The issue occurs in larger code, and since executables produced with this issue segfault in qemu, I'm forced to compile/assemble separately with clang.

@huonw huonw added the A-codegen Area: Code generation label Oct 19, 2014
@alexchandel
Copy link
Author

This does not occur with --target i686-apple-darwin:

_main:
       0:   83 ec 1c                                        subl    $28, %esp
       3:   8b 44 24 24                                     movl    36(%esp), %eax
       7:   8b 4c 24 20                                     movl    32(%esp), %ecx
...

or --target x86_64-unknown-linux-gnu:

main:
       0:   48 83 ec 18                                     subq    $24, %rsp
       4:   48 89 7c 24 10                                  movq    %rdi, 16(%rsp)
       9:   48 8b 7c 24 10                                  movq    16(%rsp), %rdi
...

@alexchandel
Copy link
Author

So, this only occurs for functions declared extern (including rust_stack_exhausted, rust_eh_personality, and the compiler-inserted main shim):

pub fn other() -> int { return 0xFFFF; }
pub extern fn ext_other() -> int { return 0xAAAA; }
_ZN5other20h3127dd56c08a3ac5baaE:
    .cfi_startproc
    jmp .LBB0_1
.LBB0_1:
    movl    $65535, %eax
    retl

...

_ZN9ext_other20ha9d431dfe83be901jaaE:
    .cfi_startproc
    pushl   %ebx
.Ltmp1:
    .cfi_def_cfa_offset 8
    subl    $8, %esp
.Ltmp2:
    .cfi_def_cfa_offset 16
.Ltmp3:
    .cfi_offset %ebx, -8
    calll   .L1$pb
.L1$pb:
    popl    %eax
.Ltmp4:
    addl    $_GLOBAL_OFFSET_TABLE_+(.Ltmp4-.L1$pb), %eax
    movl    %eax, %ebx
    calll   _ZN9ext_other10__rust_abiE
    addl    $8, %esp
    popl    %ebx
    retl

...

_ZN9ext_other10__rust_abiE:
    .cfi_startproc
    jmp .LBB2_1
.LBB2_1:
    movl    $43690, %eax
    retl

@alexchandel
Copy link
Author

Possibly related to #16259

@alexchandel
Copy link
Author

This also occurs in i686-unknown-freebsd and i686-unknown-dragonflybsd, but not i686-w64-mingw32 or i586-mingw32msvc.

Since compiling with LLVM (built from head) doesn't have this issue, is this a bug in rust-lang/llvm, or in how it's invoked?

@alexchandel
Copy link
Author

I attempted to build Rust against LLVM master, to find out if either (1) there was a bug in LLVM that's fixed upstream, or (2) there's a bug in Rust's patches. However, it turned out that a bug in our LLVM was fixed upstream, exposing several codegen bugs in Rust itself, one of them #18250.

@alexchandel
Copy link
Author

Rust now builds successfully with LLVM master (+ the four Rust LLVM patches). Yet it still produces bad assembly. See here the assembly produced by Clang, versus assembly produced by rustc, when both are given IR produced by rustc. This IR is comes from pczarn's rustboot, compiled on OS X with rust master. The assembly(/executable) produced by Clang runs correctly in QEMU, while the code produced by rustc segfaults immediately. Even assembly generated by LLC from the same IR works correctly.

For some reason, rustc is generating assembly different from clang/llvm. It's either the Rust patches, or the way LLVM is invoked by rustc.

@frewsxcv
Copy link
Member

frewsxcv commented Jun 3, 2015

@alexchandel Are you able to confirm if this is still an issue?

@steveklabnik
Copy link
Member

I'm going to take that as a no. Let me know if that's wrong, @alexchandel !

@alexchandel
Copy link
Author

@steveklabnik Just tested with rustc -C no-stack-check -Z no-landing-pads bones.rs --target i686-unknown-linux-gnu --emit asm using no_core, still an issue.

@jdm jdm reopened this Dec 17, 2015
@Mark-Simulacrum
Copy link
Member

With the following, I don't see a popl instruction, so presumably fixed, though I'm not sure. @alexchandel Can you confirm?

rustc -Z no-landing-pads t.rs --target i686-unknown-linux-gnu

#![feature(no_core, lang_items)]
#![no_core]

#[lang = "sized"]
trait Sized {}
#[lang = "copy"]
trait Copy {}

pub fn other() -> u32 { return 0xFFFF; }
pub extern fn ext_other() -> u32 { return 0xAAAA; }

emits

$ objdump -d ./libt.rlib
In archive ./libt.rlib:

t.0.o:     file format elf32-i386


Disassembly of section .text._ZN1t5other17h5beca376b5805208E:

00000000 <_ZN1t5other17h5beca376b5805208E>:
   0:	b8 ff ff 00 00       	mov    $0xffff,%eax
   5:	c3                   	ret

Disassembly of section .text._ZN1t9ext_other17he734743ecfa92ce9E:

00000000 <_ZN1t9ext_other17he734743ecfa92ce9E>:
   0:	b8 aa aa 00 00       	mov    $0xaaaa,%eax
   5:	c3                   	ret
objdump: rust.metadata.bin: File format not recognized
objdump: t.0.bytecode.deflate: File format not recognized

@Mark-Simulacrum
Copy link
Member

Closing, please reopen if this is still an issue.

lnicola pushed a commit to lnicola/rust that referenced this issue Sep 25, 2024
fix: Remove check that text of `parse_expr_from_str()` matches the produced parsed tree

This check is incorrect when we have comments and whitespace in the text.

We can strip comments, but then we still have whitespace, which we cannot strip without changing meaning for the parser. So instead I opt to remove the check, and wrap the expression in parentheses (asserting what produced is a parenthesized expression) to strengthen verification.

Fixes rust-lang#18144.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-codegen Area: Code generation
Projects
None yet
Development

No branches or pull requests

6 participants