【Getting Started with LLVM Core Libraries】P17 2.1.3 实验 Compiler-RT

本文记录了使用LLVM进行32位和64位编译实验的过程,包括遇到的环境问题及解决,重点分析了test-32bit.s和test-64bit.s汇编文件中涉及的Compiler-RT库调用。实验中展示了不同编译设置对除法运算的不同处理方式。

【Getting Started with LLVM Core Libraries】P17 2.1.3 实验 Compiler-RT

以下为书中原文

要查看编译器运行时库启动时的典型情况,可以编写一个执行64位除法的C程序来做一个简单的实验:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
int main() {
	uint64_t a = 0ULL, b = 0ULL;
	scanf("%lld %lld", &a, &b);
	printf("64-bit division is %lld\n", a / b);
	return EXIT_SUCCESS;
}

如果你有64位x86系统,请使用你的LLVM编译器来实验以下两个命令:

clang -S -m32 test.c -o test-32bit.S
clang -S test.c -o test-64bit.S

-m32标志指示编译器生成32位x86程序,而-S标志用于在test-32bit.S中为此程序生成x86汇编语言文件。如果查看这个文件,就会看到每当程序需要执行除法时都会有一个有趣的调用:

call	__udivdi3

该函数由Compiler-RT定义,并演示了将在何处使用该库。但是,如果省略-m32标志并使用64位x86编译器,即与生成test-64bit.S汇编文件的第二个编译器命令一样,则不会看到需要Compiler-RT协助的程序,因为它可以通过单个指令完成除法运算:

divq	-24(%rbp)

以下为实验中与原文不同的地方

实验32位编译

在实验中c代码命名为了testCompiler_RT.cpp

# 在实验中c代码命名为了testCompiler_RT.cpp
clang -S -m32 testCompiler_RT.cpp -o test-32bit.s

执行过程中发生了错误:

In file included from testCompiler_RT.cpp:1:
/usr/include/stdio.h:27:10: fatal error: 'bits/libc-header-start.h' file not found
#include <bits/libc-header-start.h>
         ^~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.

发现是gcc安装环境没有安装完善,安装gcc-multilib即可:

sudo apt install gcc-multilib

再次执行又出现错误:

In file included from testCompiler_RT.cpp:3:
In file included from /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/stdlib.h:36:
/usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/cstdlib:41:10: fatal error: 'bits/c++config.h' file not found
#include <bits/c++config.h>
         ^~~~~~~~~~~~~~~~~~
1 error generated.

安装g++ -multilib即可:

sudo apt install g++-multilib

运行成功后查看文件test-32bit.S发现调用命令与书中不一样(猜测书中可能有误):

# 多了一个l
calll	__udivdi3

实验64位编译

# 在实验中c代码命名为了testCompiler_RT.cpp
clang -S testCompiler_RT.cpp -o test-64bit.s

在编译过程中有警告信息:

testCompiler_RT.cpp:6:21: warning: format specifies type 'long long *' but the argument has type 'uint64_t *' (aka 'unsigned long *') [-Wformat]
        scanf("%lld %lld", &a, &b);
               ~~~~        ^~
               %ld
testCompiler_RT.cpp:6:25: warning: format specifies type 'long long *' but the argument has type 'uint64_t *' (aka 'unsigned long *') [-Wformat]
        scanf("%lld %lld", &a, &b);
                    ~~~~       ^~
                    %ld
testCompiler_RT.cpp:7:38: warning: format specifies type 'long long' but the argument has type 'unsigned long' [-Wformat]
        printf("64-bit division is %lld\n", a / b);
                                   ~~~~     ^~~~~
                                   %lu
3 warnings generated.

好在不影响编译结果。实验结果与书中相同。

以下为生成的编译文件内容

test-32bit.s

        .text
        .file   "testCompiler_RT.cpp"
        .globl  main                    # -- Begin function main
        .p2align        4, 0x90
        .type   main,@function
main:                                   # @main
        .cfi_startproc
# %bb.0:                                # %entry
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset %ebp, -8
        movl    %esp, %ebp
        .cfi_def_cfa_register %ebp
        pushl   %ebx
        pushl   %edi
        pushl   %esi
        subl    $44, %esp
        .cfi_offset %esi, -20
        .cfi_offset %edi, -16
        .cfi_offset %ebx, -12
        movl    $0, -16(%ebp)
        movl    $0, -20(%ebp)
        movl    $0, -24(%ebp)
        movl    $0, -28(%ebp)
        movl    $0, -32(%ebp)
        movl    %esp, %eax
        leal    -32(%ebp), %ecx
        movl    %ecx, 8(%eax)
        leal    -24(%ebp), %ecx
        movl    %ecx, 4(%eax)
        movl    $.L.str, (%eax)
        calll   scanf
        movl    -24(%ebp), %ecx
        movl    -20(%ebp), %edx
        movl    -32(%ebp), %esi
        movl    -28(%ebp), %edi
        movl    %esp, %ebx
        movl    %edi, 12(%ebx)
        movl    %esi, 8(%ebx)
        movl    %edx, 4(%ebx)
        movl    %ecx, (%ebx)
        movl    %eax, -36(%ebp)         # 4-byte Spill
        calll   __udivdi3
        movl    %esp, %ecx
        movl    %edx, 8(%ecx)
        movl    %eax, 4(%ecx)
        movl    $.L.str.1, (%ecx)
        calll   printf
        xorl    %ecx, %ecx
        movl    %eax, -40(%ebp)         # 4-byte Spill
        movl    %ecx, %eax
        addl    $44, %esp
        popl    %esi
        popl    %edi
        popl    %ebx
        popl    %ebp
        .cfi_def_cfa %esp, 4
        retl
.Lfunc_end0:
        .size   main, .Lfunc_end0-main
        .cfi_endproc
                                        # -- End function
        .type   .L.str,@object          # @.str
        .section        .rodata.str1.1,"aMS",@progbits,1
.L.str:
        .asciz  "%lld %lld"
        .size   .L.str, 10

        .type   .L.str.1,@object        # @.str.1
.L.str.1:
        .asciz  "64-bit division is %lld\n"
        .size   .L.str.1, 25


        .ident  "clang version 10.0.0 (http://llvm.org/git/clang.git 65acf43270ea2894dffa0d0b292b92402f80c8cb) (http://llvm.org/git/llvm.git 2c4ca6832fa6b306ee6a7010bfb80a3f2596f824)"
        .section        ".note.GNU-stack","",@progbits
        .addrsig
        .addrsig_sym scanf
        .addrsig_sym printf

test-64bit.s

        .text
        .file   "testCompiler_RT.cpp"
        .globl  main                    # -- Begin function main
        .p2align        4, 0x90
        .type   main,@function
main:                                   # @main
        .cfi_startproc
# %bb.0:                                # %entry
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset %rbp, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register %rbp
        subq    $32, %rsp
        movl    $0, -4(%rbp)
        movq    $0, -16(%rbp)
        movq    $0, -24(%rbp)
        movabsq $.L.str, %rdi
        leaq    -16(%rbp), %rsi
        leaq    -24(%rbp), %rdx
        movb    $0, %al
        callq   scanf
        movq    -16(%rbp), %rcx
        movl    %eax, -28(%rbp)         # 4-byte Spill
        movq    %rcx, %rax
        xorl    %r8d, %r8d
        movl    %r8d, %edx
        divq    -24(%rbp)
        movabsq $.L.str.1, %rdi
        movq    %rax, %rsi
        movb    $0, %al
        callq   printf
        xorl    %r8d, %r8d
        movl    %eax, -32(%rbp)         # 4-byte Spill
        movl    %r8d, %eax
        addq    $32, %rsp
        popq    %rbp
        .cfi_def_cfa %rsp, 8
        retq
.Lfunc_end0:
        .size   main, .Lfunc_end0-main
        .cfi_endproc
                                        # -- End function
        .type   .L.str,@object          # @.str
        .section        .rodata.str1.1,"aMS",@progbits,1
.L.str:
        .asciz  "%lld %lld"
        .size   .L.str, 10

        .type   .L.str.1,@object        # @.str.1
.L.str.1:
        .asciz  "64-bit division is %lld\n"
        .size   .L.str.1, 25


        .ident  "clang version 10.0.0 (http://llvm.org/git/clang.git 65acf43270ea2894dffa0d0b292b92402f80c8cb) (http://llvm.org/git/llvm.git 2c4ca6832fa6b306ee6a7010bfb80a3f2596f824)"
        .section        ".note.GNU-stack","",@progbits
        .addrsig
        .addrsig_sym scanf
        .addrsig_sym printf

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值