【问题标题】:Why does Rust emit 280 lines of assembly code to print "Hello, world"?为什么 Rust 会发出 280 行汇编代码来打印“Hello, world”?
【发布时间】:2019-12-07 10:06:01
【问题描述】:

Rust 中的一个简单的 3 行 Hello, World 程序发出一个 280 行的汇编文件以打印两个单词。同时,a pure assembly version of this program 只需要大约 15 行。为什么 Rust 版本要长这么多?

这是在 Mac OS 上。

hello.rs

fn main() {
    println!("hello world")
}

hello.s(由rustc --emit=asm hello.rs生成):

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 7
    .private_extern __ZN3std2rt10lang_start17hb4e01c1e588bf694E
    .globl  __ZN3std2rt10lang_start17hb4e01c1e588bf694E
    .p2align    4, 0x90
__ZN3std2rt10lang_start17hb4e01c1e588bf694E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $32, %rsp
    leaq    l___unnamed_1(%rip), %rax
    movq    %rdi, -8(%rbp)
    leaq    -8(%rbp), %rcx
    movq    %rcx, %rdi
    movq    %rsi, -16(%rbp)
    movq    %rax, %rsi
    movq    -16(%rbp), %rax
    movq    %rdx, -24(%rbp)
    movq    %rax, %rdx
    movq    -24(%rbp), %rcx
    callq   __ZN3std2rt19lang_start_internal17hcf96e32a124891dcE
    movq    %rax, -32(%rbp)
    movq    -32(%rbp), %rax
    addq    $32, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h275cd8632ff3ab7dE:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    callq   *(%rdi)
    callq   __ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hf5e270b394827df3E
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN3std3sys4unix7process14process_common8ExitCode6as_i3217h7e671b2505e0c229E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    movzbl  (%rdi), %eax
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN4core3fmt9Arguments6new_v117h39ef65f250941772E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movq    %rdi, %rax
    movq    $0, -16(%rbp)
    movq    %rsi, (%rdi)
    movq    %rdx, 8(%rdi)
    movq    -16(%rbp), %rdx
    movq    -8(%rbp), %rsi
    movq    %rdx, 16(%rdi)
    movq    %rsi, 24(%rdi)
    movq    %rcx, 32(%rdi)
    movq    %r8, 40(%rdi)
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h61f8ee8d3fead017E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movq    (%rdi), %rdi
    callq   __ZN4core3ops8function6FnOnce9call_once17h47f538be1b10688dE
    movl    %eax, -12(%rbp)
    movl    -12(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN4core3ops8function6FnOnce9call_once17h47f538be1b10688dE:
Lfunc_begin0:
    .cfi_startproc
    .cfi_personality 155, _rust_eh_personality
    .cfi_lsda 16, Lexception0
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $48, %rsp
    movq    %rdi, -32(%rbp)
Ltmp0:
    leaq    -32(%rbp), %rdi
    callq   __ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h275cd8632ff3ab7dE
Ltmp1:
    movl    %eax, -36(%rbp)
    jmp LBB5_1
LBB5_1:
    jmp LBB5_2
LBB5_2:
    movl    -36(%rbp), %eax
    addq    $48, %rsp
    popq    %rbp
    retq
LBB5_3:
    jmp LBB5_4
LBB5_4:
    movq    -16(%rbp), %rdi
    callq   __Unwind_Resume
    ud2
LBB5_5:
Ltmp2:
    movq    %rax, -16(%rbp)
    movl    %edx, -8(%rbp)
    jmp LBB5_3
Lfunc_end0:
    .cfi_endproc
    .section    __TEXT,__gcc_except_tab
    .p2align    2
GCC_except_table5:
Lexception0:
    .byte   255
    .byte   255
    .byte   1
    .uleb128 Lcst_end0-Lcst_begin0
Lcst_begin0:
    .uleb128 Ltmp0-Lfunc_begin0
    .uleb128 Ltmp1-Ltmp0
    .uleb128 Ltmp2-Lfunc_begin0
    .byte   0
    .uleb128 Ltmp1-Lfunc_begin0
    .uleb128 Lfunc_end0-Ltmp1
    .byte   0
    .byte   0
Lcst_end0:
    .p2align    2

    .section    __TEXT,__text,regular,pure_instructions
    .p2align    4, 0x90
__ZN4core3ptr18real_drop_in_place17h0ab16307507408dbE:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN54_$LT$$LP$$RP$$u20$as$u20$std..process..Termination$GT$6report17hf5e270b394827df3E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    xorl    %edi, %edi
    callq   __ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h03f2ed18f1614f97E
    movl    %eax, -4(%rbp)
    movl    -4(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN68_$LT$std..process..ExitCode$u20$as$u20$std..process..Termination$GT$6report17h03f2ed18f1614f97E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movb    %dil, -1(%rbp)
    leaq    -1(%rbp), %rdi
    callq   __ZN3std3sys4unix7process14process_common8ExitCode6as_i3217h7e671b2505e0c229E
    movl    %eax, -8(%rbp)
    movl    -8(%rbp), %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .p2align    4, 0x90
__ZN5hello4main17hef70db39c48df377E:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $48, %rsp
    leaq    l___unnamed_2(%rip), %rax
    xorl    %ecx, %ecx
    movl    %ecx, %r8d
    leaq    -48(%rbp), %rdi
    movq    %rax, %rsi
    movl    $1, %edx
    movl    $8, %ecx
    callq   __ZN4core3fmt9Arguments6new_v117h39ef65f250941772E
    leaq    -48(%rbp), %rdi
    callq   __ZN3std2io5stdio6_print17hd8f597a6d310dad5E
    addq    $48, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .globl  _main
    .p2align    4, 0x90
_main:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movslq  %edi, %rax
    leaq    __ZN5hello4main17hef70db39c48df377E(%rip), %rdi
    movq    %rsi, -8(%rbp)
    movq    %rax, %rsi
    movq    -8(%rbp), %rdx
    callq   __ZN3std2rt10lang_start17hb4e01c1e588bf694E
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc

    .section    __DATA,__const
    .p2align    3
l___unnamed_1:
    .quad   __ZN4core3ptr18real_drop_in_place17h0ab16307507408dbE
    .quad   8
    .quad   8
    .quad   __ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h275cd8632ff3ab7dE
    .quad   __ZN3std2rt10lang_start28_$u7b$$u7b$closure$u7d$$u7d$17h275cd8632ff3ab7dE
    .quad   __ZN4core3ops8function6FnOnce40call_once$u7b$$u7b$vtable.shim$u7d$$u7d$17h61f8ee8d3fead017E

    .section    __TEXT,__const
l___unnamed_3:
    .ascii  "hello world\n"

    .section    __DATA,__const
    .p2align    3
l___unnamed_2:
    .quad   l___unnamed_3
    .asciz  "\f\000\000\000\000\000\000"


.subsections_via_symbols

【问题讨论】:

  • 你能编译优化吗?
  • 我得到 19 lines 包括空白,所以比你的纯汇编版本少一个。
  • 为什么不呢?我没有看到问题。
  • @jmb 如果我关闭所有隐藏内容的选项,我会得到 1301 行作为您的示例,以便显示完整的汇编输出:godbolt.org/z/_Pu632
  • @RossRidge:其中大部分是调试元数据,因为 Godbolt 传递了一个选项来启用它。 (因为它的颜色突出显示以匹配 asm 和源代码行。)但是,是的,好点。

标签: macos assembly rust


【解决方案1】:

在编译代码时,编译器可以在不同方面做出许多潜在的权衡,例如:

  • 代码大小
  • 运行时性能
  • 使用的内存
  • 易于调试
  • 编译时间

大多数编译器都会为您提供一些方法来指定您希望如何考虑这些权衡。 rustc 也不例外 - 你可以使用 opt-level 代码生成选项来指定你想要的:

opt-level 这个标志让你控制优化级别。

0:没有优化,也开启 cfg(debug_assertions)。

1:基本优化

2:一些优化

3:所有优化

s:优化二进制大小

z:优化二进制大小,但也关闭循环向量化。

例如,您可以指定 -C opt-level=3 以获得最大的性能优化(在大多数情况下这也会增加编译时间)。

rustc 选项-O-C opt-level=3 的简写。

根据@jbm 提供的godbolt link,使用 -O 可以获得 19 行汇编代码。

还要注意,大多数人不直接调用 rustc,而是使用 cargo 作为构建控制工具。 cargo build 子命令允许您指定构建配置文件,该配置文件确定应用的优化级别等内容。 --release 标志调用适用于发布版本的优化配置文件。

【讨论】:

    猜你喜欢
    • 2020-02-03
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-04
    • 1970-01-01
    相关资源
    最近更新 更多