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

被折叠的 条评论
为什么被折叠?



