Cross toolchain under linux

怎样构建一个不依赖gcc/binutils的llvm/clang Linux工具链

cjacker posted @ 2014年9月10日 16:32 in 代码 , 9166 阅读

本文不讲原理,只讲步骤。需要了解什么是unwind,crtbengin/end,ehtable以及libgcc_s/libgcc_eh或者c++abi/supc++的,请查阅相关文档。

1,Build llvm/clang/lldb/lld 3.5.0等组件

1.0  准备:

至少需要从llvm.org下载llvm, cfe, lldb, compiler-rt,lld等3.5.0版本的代码。

$tar xf llvm-3.5.0.src.tar.gz

$cd llvm-3.5.0.src

$mkdir -p tools/clang
$mkdir -p tools/clang/tools/extra
$mkdir -p tools/lld
$mkdir -p projects/compiler-rt

$tar xf cfe-3.5.0.src.tar.xz -C tools/clang --strip-components=1
$tar xf compiler-rt-3.5.0.src.tar.xz -C projects/compiler-rt --strip-components=1
$tar xf lldb-3.5.0.src.tar.xz -C tools/clang/tools/extra --strip-components=1
$tar xf lld-3.5.0.src.tar.xz -C tools/lld --strip-components=1

 

1.1 【可选】使用clang --stdlib=libc++时,自动添加-lc++abi。

libc++组件可以使用gcc libstdc++的supc++ ABI,也可以使用c++abi,cxxrt等,实际上自动添加-lc++abi是不必要的,这里这么处理,主要是为了方便起见。实际上完全可以在“clang++ -stdlib=libc++”时再手工添加-lc++abi给链接器。

这里涉及到链接时DSO隐式还是显式的问题,早些时候ld在链接库时会自动引入由库引入的依赖动态库,后来因为这个行为的不可控性,所以ld链接器的行为做了修改,需要显式的写明所有需要链接的动态库,才会有手工添加-lc++abi这种情况出现。

--- llvm-3.0.src/tools/clang/lib/Driver/ToolChain.cpp   2012-03-26 18:49:06.663029075 +0800
+++ llvm-3.0.srcn/tools/clang/lib/Driver/ToolChain.cpp  2012-03-26 19:36:04.260071355 +0800
@@ -251,6 +251,7 @@
   switch (Type) {
   case ToolChain::CST_Libcxx:
     CmdArgs.push_back("-lc++");
+    CmdArgs.push_back("-lc++abi");
     break;

   case ToolChain::CST_Libstdcxx:

 

1.2 【必要】给clang++添加-fnolibgcc开关。

这个开关主要用来控制是否连接到libgcc或者libunwind。

注:libgcc不等于libunwind。libgcc_eh以及supc++的一部分跟libunwind功能相当。

注:libgcc_s和compiler_rt的一部分相当。

 

这个补丁是必要的,不会对clang的正常使用造成任何影响,只有在使用“-fnolibgcc"参数时才会起作用。

之所以进行了很多unwind的引入,主要是为了避免不必要的符号缺失麻烦,这里的处理相对来说是干净的,通过as-needed规避了不必要的引入。

--- llvm-static-3.5.0.bak/tools/clang/lib/Driver/Tools.cpp	2014-09-10 13:46:02.581543888 +0800
+++ llvm-static-3.5.0/tools/clang/lib/Driver/Tools.cpp	2014-09-10 16:03:37.559019321 +0800
@@ -2060,9 +2060,15 @@
                                           ".a");
 
   CmdArgs.push_back(Args.MakeArgString(LibClangRT));
-  CmdArgs.push_back("-lgcc_s");
-  if (TC.getDriver().CCCIsCXX())
-    CmdArgs.push_back("-lgcc_eh");
+  if (Args.hasArg(options::OPT_fnolibgcc)) {
+    CmdArgs.push_back("--as-needed");
+    CmdArgs.push_back("-lunwind");
+    CmdArgs.push_back("--no-as-needed");
+  } else {
+    CmdArgs.push_back("-lgcc_s");
+    if (TC.getDriver().CCCIsCXX())
+      CmdArgs.push_back("-lgcc_eh");
+  }
 }
 
 static void addProfileRT(
@@ -7150,24 +7156,50 @@
   bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android;
   bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) ||
                       Args.hasArg(options::OPT_static);
+
+
+
   if (!D.CCCIsCXX())
-    CmdArgs.push_back("-lgcc");
+    if (Args.hasArg(options::OPT_fnolibgcc)) {
+        CmdArgs.push_back("--as-needed");
+        CmdArgs.push_back("-lunwind");
+        CmdArgs.push_back("--no-as-needed");
+    } else
+        CmdArgs.push_back("-lgcc");
 
   if (StaticLibgcc || isAndroid) {
     if (D.CCCIsCXX())
-      CmdArgs.push_back("-lgcc");
+    if (Args.hasArg(options::OPT_fnolibgcc)) {
+        CmdArgs.push_back("--as-needed");
+        CmdArgs.push_back("-lunwind");
+        CmdArgs.push_back("--no-as-needed");
+    } else
+        CmdArgs.push_back("-lgcc");
   } else {
     if (!D.CCCIsCXX())
       CmdArgs.push_back("--as-needed");
-    CmdArgs.push_back("-lgcc_s");
+    if (Args.hasArg(options::OPT_fnolibgcc))
+        CmdArgs.push_back("-lunwind");
+    else
+        CmdArgs.push_back("-lgcc_s");
     if (!D.CCCIsCXX())
       CmdArgs.push_back("--no-as-needed");
   }
 
   if (StaticLibgcc && !isAndroid)
-    CmdArgs.push_back("-lgcc_eh");
+    if (Args.hasArg(options::OPT_fnolibgcc)) {
+        CmdArgs.push_back("--as-needed");
+        CmdArgs.push_back("-lunwind");
+        CmdArgs.push_back("--no-as-needed");
+    } else
+        CmdArgs.push_back("-lgcc_eh");
   else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX())
-    CmdArgs.push_back("-lgcc");
+    if (Args.hasArg(options::OPT_fnolibgcc)) {
+        CmdArgs.push_back("--as-needed");
+        CmdArgs.push_back("-lunwind");
+        CmdArgs.push_back("--no-as-needed");
+    } else
+        CmdArgs.push_back("-lgcc");
 
   // According to Android ABI, we have to link with libdl if we are
   // linking with non-static libgcc.
--- llvm-static-3.5.0.bak/tools/clang/include/clang/Driver/Options.td	2014-08-07 12:51:51.000000000 +0800
+++ llvm-static-3.5.0/tools/clang/include/clang/Driver/Options.td	2014-09-10 13:36:34.598511176 +0800
@@ -788,6 +788,7 @@
 def fomit_frame_pointer : Flag<["-"], "fomit-frame-pointer">, Group<f_Group>;
 def fopenmp : Flag<["-"], "fopenmp">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
 def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group<f_Group>, Flags<[CC1Option]>;
+def fnolibgcc : Flag<["-"], "fnolibgcc">, Group<f_Group>, Flags<[CC1Option, NoArgumentUnused]>;
 def fno_optimize_sibling_calls : Flag<["-"], "fno-optimize-sibling-calls">, Group<f_Group>;
 def foptimize_sibling_calls : Flag<["-"], "foptimize-sibling-calls">, Group<f_Group>;
 def force__cpusubtype__ALL : Flag<["-"], "force_cpusubtype_ALL">;

1.3 llvm的其他补丁。

llvm/clang将gcc toolchain的路径hard code在代码中,请查阅tools/clang/lib/Driver/ToolChains.cpp。

找到x86_64-redhat-linux之类的字符串。

如果没有你系统特有的gcc tripple string,请自行添加。

这个tripple string主要是给llvm/clang搜索gcc头文件等使用的,不影响本文要构建的toolchain

 

1.4 构建clang/llvm/lldb

本文使用ninja。顺便说一下,llvm支持configure和cmake两种构建方式。可能是因为工程太大,这两种构建方式的工程文件都有各种缺陷(主要表现在开关选项上,比如configure有,但是cmake却没有等)。llvm-3.4.1就是因为cmake工程文件的错误而导致了3.4.2版本的发布。

综合而言,cmake+ninja的方式是目前最快的构建方式之一,可以将构建时间缩短一半以上。

mkdir build
cd build

cmake \
    -G Ninja \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DCMAKE_BUILD_TYPE="Release" \
    -DCMAKE_CXX_FLAGS="-std=c++11" \
    -DBUILD_SHARED_LIBS=OFF \
    -DLLVM_ENABLE_PIC=ON \
    -DLLVM_TARGETS_TO_BUILD="all" \
    -DCLANG_VENDOR="MyOS" ..

ninja

ninja install

    

如果系统原来就有clang/clang++的可用版本,可以添加:

    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++ \

这样就会使用系统的clang++来构建llvm/clang

 

2,测试clang/clang++。

自己找几个简单的c/cpp/objc等编译测试一下即可。完整测试可以在构建时作ninja check-all

 

3,libunwind/libc++/libc++abi,一套不依赖libgcc, libstdc++的c++运行库。

3.1 从https://github.com/pathscale/libunwind 获取代码。

libunwind有很多个实现,比如gnu的libunwind, path64的libunwind,还有libcxxabi自带的Unwinder.

这里作下说明:

1),gnu的libunwind会有符号缺失和冲突。

2),libcxxabi自带的Unwinder是给mac和ios用的,也就是只能在darwin体系构建。目前Linux的实现仍然不全,等linux实现完整了或许就不再需要path64的unwind实现了。

暂时建议使用pathscale的unwind实现。

mkdir -p build
cd build
cmake -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_C_FLAGS="-m64" ..
ninja

mkdir -p /usr/lib
cp src/libunwind.so /usr/lib
cp src/libunwind.a /usr/lib

 

3.2 第一次构建libcxx.

必须先构建一次libcxx,以便后面构建libcxxabi。这里构建的libcxx实际上是使用gcc的libgcc/stdc++/supc++的。

打上这个补丁来禁止libgcc的引入:

diff -Nur libcxx/cmake/config-ix.cmake libcxxn/cmake/config-ix.cmake
--- libcxx/cmake/config-ix.cmake    2014-06-25 06:57:50.000000000 +0800
+++ libcxxn/cmake/config-ix.cmake   2014-06-25 09:05:24.980350544 +0800
@@ -28,5 +28,4 @@
 check_library_exists(c printf "" LIBCXX_HAS_C_LIB)
 check_library_exists(m ccos "" LIBCXX_HAS_M_LIB)
 check_library_exists(rt clock_gettime "" LIBCXX_HAS_RT_LIB)
-check_library_exists(gcc_s __gcc_personality_v0 "" LIBCXX_HAS_GCC_S_LIB)

 

编译安装:

mkdir build
cd build
cmake \
    -G Ninja \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++  \
    ..
ninja
ninja install


3.3,测试第一次构建的libcxx。

使用"clang++ -stdlib=libc++  -o test test.cpp -lstdc++"编译简单c++代码,检查是否出错。(如果前面构建clang是已经apply了c++abi的链接补丁,这里会出现找不到c++abi的情况,跳过即可)

使用"ldd test"查看test二进制动态库使用情况。可以发现,test依赖于libgcc_s/libc++/libstdc++。(多少有些不爽了吧?使用了libc++居然还要依赖libstdc++?)

 

3.4,构建libcxxabi。

打上以下补丁,让libcxxabi链接到libc++,并生成静态库。

diff -Nur libcxxabi/lib/buildit libcxxabin/lib/buildit
--- libcxxabi/lib/buildit   2013-12-05 20:36:16.000000000 +0800
+++ libcxxabin/lib/buildit  2014-06-25 08:14:25.922459892 +0800
@@ -70,7 +70,7 @@
     SOEXT=so
     LDSHARED_FLAGS="-o libc++abi.so.1.0 \
         -shared -nodefaultlibs -Wl,-soname,libc++abi.so.1 \
-        -lpthread -lrt -lc -lstdc++"
+        -lpthread -lrt -lc -lc++"
     ;;
 esac

@@ -92,6 +92,8 @@
   ;;
 esac
 $CC *.o $RC_CFLAGS $LDSHARED_FLAGS $EXTRA_FLAGS
+ar rc libc++abi.a *.o
+ranlib libc++abi.a

 if [ -z $RC_XBS ]
 then     

 

编译安装:

cd lib
export CC="clang -fPIC"
export CXX="clang++ -fPIC"
./buildit
install -m 0644 lib/libc++abi.so.1.0 /usr/lib
install -m 0644 lib/libc++abi.a /usr/lib
cp -r include/* /usr/include
cd /usr/lib
ln -s libc++abi.so.1.0 libc++abi.so.1
ln -s libc++abi.so.1.0 libc++abi.so

 

3.5,第二次构建libcxx,使其使用c++abi,并同时构建出静态库。

仍然要打上禁用_gcc_personality_v0的补丁。

mkdir build-shared
cd build-shared
cmake \
    -G Ninja \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++  \
    -DLIBCXX_CXX_ABI=libcxxabi \
    -DLIBCXX_LIBCXXABI_INCLUDE_PATHS="/usr/include" \
    ..
ninja
ninja install
cd ..

mkdir build-static
cd build-static
cmake \
    -G Ninja \
    -DCMAKE_INSTALL_PREFIX=/usr \
    -DCMAKE_C_COMPILER=clang \
    -DCMAKE_CXX_COMPILER=clang++  \
    -DLIBCXX_CXX_ABI=libcxxabi \
    -DLIBCXX_LIBCXXABI_INCLUDE_PATHS="/usr/include" \
    -DLIBCXX_ENABLE_SHARED=OFF \
    ..
ninja
ninja install
cd ..

 

至此,unwind/libcxx/libcxxabi构建完成,并摆脱了gcc运行时库libgcc/libstdc++的依赖。

3.6,测试验证一下

"ld -lc++ -lc++abi -lgcc_s"

"ld -lc++ -lc++abi -lunwind"

这两种情况都应该可以满足符号依赖,不存在符号找不到的情况。(主要是_Unwind_符号)

至此:

使用:

clang++ -o test test.cpp
ldd test

test将链接到stdc++/gcc_s. 这是默认使用gcc runtime的情况,其二进制也会跟gcc生成的二进制完全兼容。

clang++ -fnolibgcc -o test test.cpp
ldd test

test将链接到stdc++/unwind.(注:gcc_s跟unwind的功能不完全一样,但互有交集实现)

clang++ -stdlib=libc++ -o test test.cpp
ldd test

test将链接到c++/c++abi/gcc_s(已经剥离了stdc++依赖,但仍然使用gcc_s,也是因为_Unwind_符号的原因)

clang++ -stdlib=libc++ -fnolibgcc -o test test.cpp
ldd test

test将链接到c++/c++abi/unwind.(这大概是很多同志想要的。)

 

4. crtbegin.o/crtend.o

 

这两货是什么作用可以查一下文档,gcc默认参数构建的每个二进制中,这两个.o都被链接进去了,具体构建链接参数,可以在clang编译代码时加 -v查看。默认情况下,clang会使用gcc的crtbegin/end。

这里我们用Netbsd的实现替代了gcc的实现。

x86_64的汇编代码从这里下载: http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/csu/arch/x86_64/?only_with_tag=MAIN。

注意安装路径,这是clang最优先的搜索路径。

as crtbegin.S -o /usr/lib/clang/3.5.0/crtbegin.o
as crtbegin.S -o /usr/lib/clang/3.5.0/crtbeginS.o
as crtbegin.S -o /usr/lib/clang/3.5.0/crtbeginT.o

as crtend.S -o /usr/lib/clang/3.5.0/crtend.o
as crtend.S -o /usr/lib/clang/3.5.0/crtendS.o
as crtend.S -o /usr/lib/clang/3.5.0/crtendT.o

 

5,至此,我们基本获得了一条不依赖gcc任何组件的clang/llvm工具链。

编译时通过-fnolibgcc参数以及-stdlib=libc++参数的配合,可以完成c/c++代码的编译并脱离对gcc运行时库的依赖。

 

6,使用新的clang toolchain完成上述所有组件的bootstrap。(也就是用新toolchain重新编译llvm/clang)

具体构建过程参考步骤1.

在apply上述补丁的同时,需要apply以下补丁。

主要原因是ehtable支持需要调用register_frame实现,这是libgcc特有的实现。

--- llvm-3.4.2.src.bak/lib/ExecutionEngine/RTDyldMemoryManager.cpp  2013-12-24 14:50:45.000000000 +0800
+++ llvm-3.4.2.src/lib/ExecutionEngine/RTDyldMemoryManager.cpp  2014-06-25 14:11:53.721693229 +0800
@@ -33,12 +33,7 @@
 RTDyldMemoryManager::~RTDyldMemoryManager() {}

 // Determine whether we can register EH tables.
-#if (defined(__GNUC__) && !defined(__ARM_EABI__) && !defined(__ia64__) && \
-     !defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__))
-#define HAVE_EHTABLE_SUPPORT 1
-#else
 #define HAVE_EHTABLE_SUPPORT 0
-#endif

 #if HAVE_EHTABLE_SUPPORT
 extern "C" void __register_frame(void*);


在编译时,注意增加clang/clang++参数如下:

-DCMAKE_CXX_FLAGS="-std=c++11 --stdlib=libc++ -fnolibgcc -fPIC"
-DCMAKE_C_FLAGS="-fPIC" 

 

7,使用lld。

lld的使用方法非常简单,只需要将/usr/bin/lld链接成/usr/bin/ld即可。

更通常的情况,是使用alternatives来管理和切换多个ld(至少,目前我们有binutils的ld.bfd, google的gold以及llvm的lld可用)

根据经验,lld应该可以胜任大部分的链接工作,但毕竟是新生项目,且仍然有大量的gnu ld的参数没有支持,所以,这里不建议未经测试和验证的就在生产环境使用。

此外,完全脱离binutils目前也不太可能,毕竟出了gnu as/ld,binutils也提供了ar,ranlib等utility。虽然llvm提供了llvm-ar等,但这些llvm utility是处理llvm bc IR字节码的,并不是用来处理系统目标文件的工具。

8,__gcc_personality_v0符号问题。

在部分静态库或者动态库链接时,如果强制使用-fnolibgcc参数禁止掉libgcc的使用,可能会出现__gcc_personality_v0符号缺失问题,这个问题的解决方法有以下两个:

7.1 添加--rtlib=compiler-rt, llvm的compiler-rt有该符号的完整实现。

7.2 或者为libunwind打上这个补丁,将实现放到libunwind中。

diff -Nur libunwind/src/CMakeLists.txt libunwindn/src/CMakeLists.txt
--- libunwind/src/CMakeLists.txt	2014-06-25 07:14:23.000000000 +0800
+++ libunwindn/src/CMakeLists.txt	2014-06-25 11:48:55.139999875 +0800
@@ -50,6 +50,8 @@
     dwarf/Lpe.c
     dwarf/Lstep.c
     dwarf/Lfind_proc_info-lsb.c
+    gcc_personality_v0/gcc_personality_v0.c 
+    gcc_personality_v0/int_util.c 
    )
 
 
diff -Nur libunwind/src/gcc_personality_v0/gcc_personality_v0.c libunwindn/src/gcc_personality_v0/gcc_personality_v0.c
--- libunwind/src/gcc_personality_v0/gcc_personality_v0.c	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/gcc_personality_v0.c	2014-06-25 11:47:54.010002060 +0800
@@ -0,0 +1,247 @@
+/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
+ *
+ *      	       The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ */
+
+#include "int_lib.h"
+
+/*
+ * _Unwind_* stuff based on C++ ABI public documentation
+ * http://refspecs.freestandards.org/abi-eh-1.21.html
+ */
+
+typedef enum {
+    _URC_NO_REASON = 0,
+    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+    _URC_FATAL_PHASE2_ERROR = 2,
+    _URC_FATAL_PHASE1_ERROR = 3,
+    _URC_NORMAL_STOP = 4,
+    _URC_END_OF_STACK = 5,
+    _URC_HANDLER_FOUND = 6,
+    _URC_INSTALL_CONTEXT = 7,
+    _URC_CONTINUE_UNWIND = 8
+} _Unwind_Reason_Code;
+
+typedef enum {
+    _UA_SEARCH_PHASE = 1,
+    _UA_CLEANUP_PHASE = 2,
+    _UA_HANDLER_FRAME = 4,
+    _UA_FORCE_UNWIND = 8,
+    _UA_END_OF_STACK = 16
+} _Unwind_Action;
+
+typedef struct _Unwind_Context* _Unwind_Context_t;
+
+struct _Unwind_Exception {
+    uint64_t                exception_class;
+    void                    (*exception_cleanup)(_Unwind_Reason_Code reason, 
+                                                 struct _Unwind_Exception* exc);
+    uintptr_t                private_1;    
+    uintptr_t                private_2;    
+};
+
+extern const uint8_t*    _Unwind_GetLanguageSpecificData(_Unwind_Context_t c);
+extern void              _Unwind_SetGR(_Unwind_Context_t c, int i, uintptr_t n);
+extern void              _Unwind_SetIP(_Unwind_Context_t, uintptr_t new_value);
+extern uintptr_t         _Unwind_GetIP(_Unwind_Context_t context);
+extern uintptr_t         _Unwind_GetRegionStart(_Unwind_Context_t context);
+
+
+/*
+ * Pointer encodings documented at:
+ *   http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
+ */
+
+#define DW_EH_PE_omit      0xff  /* no data follows */
+
+#define DW_EH_PE_absptr    0x00
+#define DW_EH_PE_uleb128   0x01
+#define DW_EH_PE_udata2    0x02
+#define DW_EH_PE_udata4    0x03
+#define DW_EH_PE_udata8    0x04
+#define DW_EH_PE_sleb128   0x09
+#define DW_EH_PE_sdata2    0x0A
+#define DW_EH_PE_sdata4    0x0B
+#define DW_EH_PE_sdata8    0x0C
+
+#define DW_EH_PE_pcrel     0x10
+#define DW_EH_PE_textrel   0x20
+#define DW_EH_PE_datarel   0x30
+#define DW_EH_PE_funcrel   0x40
+#define DW_EH_PE_aligned   0x50  
+#define DW_EH_PE_indirect  0x80 /* gcc extension */
+
+
+
+/* read a uleb128 encoded value and advance pointer */
+static uintptr_t readULEB128(const uint8_t** data)
+{
+    uintptr_t result = 0;
+    uintptr_t shift = 0;
+    unsigned char byte;
+    const uint8_t* p = *data;
+    do {
+        byte = *p++;
+        result |= (byte & 0x7f) << shift;
+        shift += 7;
+    } while (byte & 0x80);
+    *data = p;
+    return result;
+}
+
+/* read a pointer encoded value and advance pointer */
+static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
+{
+    const uint8_t* p = *data;
+    uintptr_t result = 0;
+
+    if ( encoding == DW_EH_PE_omit ) 
+        return 0;
+
+    /* first get value */
+    switch (encoding & 0x0F) {
+        case DW_EH_PE_absptr:
+            result = *((uintptr_t*)p);
+            p += sizeof(uintptr_t);
+            break;
+        case DW_EH_PE_uleb128:
+            result = readULEB128(&p);
+            break;
+        case DW_EH_PE_udata2:
+            result = *((uint16_t*)p);
+            p += sizeof(uint16_t);
+            break;
+        case DW_EH_PE_udata4:
+            result = *((uint32_t*)p);
+            p += sizeof(uint32_t);
+            break;
+        case DW_EH_PE_udata8:
+            result = *((uint64_t*)p);
+            p += sizeof(uint64_t);
+            break;
+        case DW_EH_PE_sdata2:
+            result = *((int16_t*)p);
+            p += sizeof(int16_t);
+            break;
+        case DW_EH_PE_sdata4:
+            result = *((int32_t*)p);
+            p += sizeof(int32_t);
+            break;
+        case DW_EH_PE_sdata8:
+            result = *((int64_t*)p);
+            p += sizeof(int64_t);
+            break;
+        case DW_EH_PE_sleb128:
+        default:
+            /* not supported */
+            compilerrt_abort();
+            break;
+    }
+
+    /* then add relative offset */
+    switch ( encoding & 0x70 ) {
+        case DW_EH_PE_absptr:
+            /* do nothing */
+            break;
+        case DW_EH_PE_pcrel:
+            result += (uintptr_t)(*data);
+            break;
+        case DW_EH_PE_textrel:
+        case DW_EH_PE_datarel:
+        case DW_EH_PE_funcrel:
+        case DW_EH_PE_aligned:
+        default:
+            /* not supported */
+            compilerrt_abort();
+            break;
+    }
+
+    /* then apply indirection */
+    if (encoding & DW_EH_PE_indirect) {
+        result = *((uintptr_t*)result);
+    }
+
+    *data = p;
+    return result;
+}
+
+
+/*
+ * The C compiler makes references to __gcc_personality_v0 in
+ * the dwarf unwind information for translation units that use
+ * __attribute__((cleanup(xx))) on local variables.
+ * This personality routine is called by the system unwinder
+ * on each frame as the stack is unwound during a C++ exception
+ * throw through a C function compiled with -fexceptions.
+ */
+#if __arm__
+// the setjump-longjump based exceptions personality routine has a different name
+_Unwind_Reason_Code __gcc_personality_sj0(int version, _Unwind_Action actions,
+         uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+         _Unwind_Context_t context)
+#else
+_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
+         uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
+         _Unwind_Context_t context)
+#endif
+{
+    /* Since C does not have catch clauses, there is nothing to do during */
+    /* phase 1 (the search phase). */
+    if ( actions & _UA_SEARCH_PHASE ) 
+        return _URC_CONTINUE_UNWIND;
+        
+    /* There is nothing to do if there is no LSDA for this frame. */
+    const uint8_t* lsda = _Unwind_GetLanguageSpecificData(context);
+    if ( lsda == (uint8_t*) 0 )
+        return _URC_CONTINUE_UNWIND;
+
+    uintptr_t pc = _Unwind_GetIP(context)-1;
+    uintptr_t funcStart = _Unwind_GetRegionStart(context);
+    uintptr_t pcOffset = pc - funcStart;
+
+    /* Parse LSDA header. */
+    uint8_t lpStartEncoding = *lsda++;
+    if (lpStartEncoding != DW_EH_PE_omit) {
+        readEncodedPointer(&lsda, lpStartEncoding); 
+    }
+    uint8_t ttypeEncoding = *lsda++;
+    if (ttypeEncoding != DW_EH_PE_omit) {
+        readULEB128(&lsda);  
+    }
+    /* Walk call-site table looking for range that includes current PC. */
+    uint8_t         callSiteEncoding = *lsda++;
+    uint32_t        callSiteTableLength = readULEB128(&lsda);
+    const uint8_t*  callSiteTableStart = lsda;
+    const uint8_t*  callSiteTableEnd = callSiteTableStart + callSiteTableLength;
+    const uint8_t* p=callSiteTableStart;
+    while (p < callSiteTableEnd) {
+        uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
+        uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
+        uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+        readULEB128(&p); /* action value not used for C code */
+        if ( landingPad == 0 )
+            continue; /* no landing pad for this entry */
+        if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
+            /* Found landing pad for the PC.
+             * Set Instruction Pointer to so we re-enter function 
+             * at landing pad. The landing pad is created by the compiler
+             * to take two parameters in registers.
+	     */
+            _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 
+                                                (uintptr_t)exceptionObject);
+            _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
+            _Unwind_SetIP(context, funcStart+landingPad);
+            return _URC_INSTALL_CONTEXT;
+        }
+    }
+    
+    /* No landing pad found, continue unwinding. */
+    return _URC_CONTINUE_UNWIND;
+}
+
diff -Nur libunwind/src/gcc_personality_v0/int_endianness.h libunwindn/src/gcc_personality_v0/int_endianness.h
--- libunwind/src/gcc_personality_v0/int_endianness.h	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/int_endianness.h	2014-06-25 11:47:54.010002060 +0800
@@ -0,0 +1,111 @@
+/* ===-- int_endianness.h - configuration header for compiler-rt ------------===
+ *
+ *		       The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file is a configuration header for compiler-rt.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_ENDIANNESS_H
+#define INT_ENDIANNESS_H
+
+#if defined(__SVR4) && defined(__sun)
+#include <sys/byteorder.h>
+
+#if defined(_BIG_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN    1
+#elif defined(_LITTLE_ENDIAN)
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN    0
+#else /* !_LITTLE_ENDIAN */
+#error "unknown endianness"
+#endif /* !_LITTLE_ENDIAN */
+
+#endif /* Solaris and AuroraUX. */
+
+/* .. */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__minix)
+#include <sys/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN    1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN    0
+#endif /* _BYTE_ORDER */
+
+#endif /* *BSD */
+
+#if defined(__OpenBSD__) || defined(__Bitrig__)
+#include <machine/endian.h>
+
+#if _BYTE_ORDER == _BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN    1
+#elif _BYTE_ORDER == _LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN    0
+#endif /* _BYTE_ORDER */
+
+#endif /* OpenBSD and Bitrig. */
+
+/* .. */
+
+/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the compiler (at least with GCC) */
+#if defined(__APPLE__) && defined(__MACH__) || defined(__ellcc__ )
+
+#ifdef __BIG_ENDIAN__
+#if __BIG_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN    1
+#endif
+#endif /* __BIG_ENDIAN__ */
+
+#ifdef __LITTLE_ENDIAN__
+#if __LITTLE_ENDIAN__
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN    0
+#endif
+#endif /* __LITTLE_ENDIAN__ */
+
+#endif /* Mac OSX */
+
+/* .. */
+
+#if defined(__linux__)
+#include <endian.h>
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 0
+#define _YUGA_BIG_ENDIAN    1
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN    0
+#endif /* __BYTE_ORDER */
+
+#endif /* GNU/Linux */
+
+#if defined(_WIN32)
+
+#define _YUGA_LITTLE_ENDIAN 1
+#define _YUGA_BIG_ENDIAN    0
+
+#endif /* Windows */
+
+/* . */
+
+#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN)
+#error Unable to determine endian
+#endif /* Check we found an endianness correctly. */
+
+#endif /* INT_ENDIANNESS_H */
diff -Nur libunwind/src/gcc_personality_v0/int_lib.h libunwindn/src/gcc_personality_v0/int_lib.h
--- libunwind/src/gcc_personality_v0/int_lib.h	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/int_lib.h	2014-06-25 11:47:54.009002060 +0800
@@ -0,0 +1,46 @@
+/* ===-- int_lib.h - configuration header for compiler-rt  -----------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file is a configuration header for compiler-rt.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_LIB_H
+#define INT_LIB_H
+
+/* Assumption: Signed integral is 2's complement. */
+/* Assumption: Right shift of signed negative is arithmetic shift. */
+/* Assumption: Endianness is little or big (not mixed). */
+
+/* ABI macro definitions */
+
+#if __ARM_EABI__
+# define ARM_EABI_FNALIAS(aeabi_name, name)         \
+  void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
+# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
+#else
+# define ARM_EABI_FNALIAS(aeabi_name, name)
+# define COMPILER_RT_ABI
+#endif
+
+/* Include the standard compiler builtin headers we use functionality from. */
+#include <limits.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <float.h>
+
+/* Include the commonly used internal type definitions. */
+#include "int_types.h"
+
+/* Include internal utility function declarations. */
+#include "int_util.h"
+
+#endif /* INT_LIB_H */
diff -Nur libunwind/src/gcc_personality_v0/int_math.h libunwindn/src/gcc_personality_v0/int_math.h
--- libunwind/src/gcc_personality_v0/int_math.h	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/int_math.h	2014-06-25 11:47:54.009002060 +0800
@@ -0,0 +1,67 @@
+/* ===-- int_math.h - internal math inlines ---------------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This file is not part of the interface of this library.
+ *
+ * This file defines substitutes for the libm functions used in some of the
+ * compiler-rt implementations, defined in such a way that there is not a direct
+ * dependency on libm or math.h. Instead, we use the compiler builtin versions
+ * where available. This reduces our dependencies on the system SDK by foisting
+ * the responsibility onto the compiler.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef INT_MATH_H
+#define INT_MATH_H
+
+#ifndef __has_builtin
+#  define  __has_builtin(x) 0
+#endif
+
+#define CRT_INFINITY __builtin_huge_valf()
+
+#define crt_isinf(x) __builtin_isinf((x))
+#define crt_isnan(x) __builtin_isnan((x))
+
+/* Define crt_isfinite in terms of the builtin if available, otherwise provide
+ * an alternate version in terms of our other functions. This supports some
+ * versions of GCC which didn't have __builtin_isfinite.
+ */
+#if __has_builtin(__builtin_isfinite)
+#  define crt_isfinite(x) __builtin_isfinite((x))
+#else
+#  define crt_isfinite(x) \
+  __extension__(({ \
+      __typeof((x)) x_ = (x); \
+      !crt_isinf(x_) && !crt_isnan(x_); \
+    }))
+#endif
+
+#define crt_copysign(x, y) __builtin_copysign((x), (y))
+#define crt_copysignf(x, y) __builtin_copysignf((x), (y))
+#define crt_copysignl(x, y) __builtin_copysignl((x), (y))
+
+#define crt_fabs(x) __builtin_fabs((x))
+#define crt_fabsf(x) __builtin_fabsf((x))
+#define crt_fabsl(x) __builtin_fabsl((x))
+
+#define crt_fmax(x, y) __builtin_fmax((x), (y))
+#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y))
+#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y))
+
+#define crt_logb(x) __builtin_logb((x))
+#define crt_logbf(x) __builtin_logbf((x))
+#define crt_logbl(x) __builtin_logbl((x))
+
+#define crt_scalbn(x, y) __builtin_scalbn((x), (y))
+#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y))
+#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y))
+
+#endif /* INT_MATH_H */
diff -Nur libunwind/src/gcc_personality_v0/int_types.h libunwindn/src/gcc_personality_v0/int_types.h
--- libunwind/src/gcc_personality_v0/int_types.h	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/int_types.h	2014-06-25 11:47:54.009002060 +0800
@@ -0,0 +1,140 @@
+/* ===-- int_lib.h - configuration header for compiler-rt  -----------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file is not part of the interface of this library.
+ *
+ * This file defines various standard types, most importantly a number of unions
+ * used to access parts of larger types.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef INT_TYPES_H
+#define INT_TYPES_H
+
+#include "int_endianness.h"
+
+typedef      int si_int;
+typedef unsigned su_int;
+
+typedef          long long di_int;
+typedef unsigned long long du_int;
+
+typedef union
+{
+    di_int all;
+    struct
+    {
+#if _YUGA_LITTLE_ENDIAN
+        su_int low;
+        si_int high;
+#else
+        si_int high;
+        su_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+    }s;
+} dwords;
+
+typedef union
+{
+    du_int all;
+    struct
+    {
+#if _YUGA_LITTLE_ENDIAN
+        su_int low;
+        su_int high;
+#else
+        su_int high;
+        su_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+    }s;
+} udwords;
+
+#if __x86_64
+
+typedef int      ti_int __attribute__ ((mode (TI)));
+typedef unsigned tu_int __attribute__ ((mode (TI)));
+
+typedef union
+{
+    ti_int all;
+    struct
+    {
+#if _YUGA_LITTLE_ENDIAN
+        du_int low;
+        di_int high;
+#else
+        di_int high;
+        du_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+    }s;
+} twords;
+
+typedef union
+{
+    tu_int all;
+    struct
+    {
+#if _YUGA_LITTLE_ENDIAN
+        du_int low;
+        du_int high;
+#else
+        du_int high;
+        du_int low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+    }s;
+} utwords;
+
+static inline ti_int make_ti(di_int h, di_int l) {
+    twords r;
+    r.s.high = h;
+    r.s.low = l;
+    return r.all;
+}
+
+static inline tu_int make_tu(du_int h, du_int l) {
+    utwords r;
+    r.s.high = h;
+    r.s.low = l;
+    return r.all;
+}
+
+#endif /* __x86_64 */
+
+typedef union
+{
+    su_int u;
+    float f;
+} float_bits;
+
+typedef union
+{
+    udwords u;
+    double  f;
+} double_bits;
+
+typedef struct
+{
+#if _YUGA_LITTLE_ENDIAN
+    udwords low;
+    udwords high;
+#else
+    udwords high;
+    udwords low;
+#endif /* _YUGA_LITTLE_ENDIAN */
+} uqwords;
+
+typedef union
+{
+    uqwords     u;
+    long double f;
+} long_double_bits;
+
+#endif /* INT_TYPES_H */
+
diff -Nur libunwind/src/gcc_personality_v0/int_util.c libunwindn/src/gcc_personality_v0/int_util.c
--- libunwind/src/gcc_personality_v0/int_util.c	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/int_util.c	2014-06-25 11:59:12.934977792 +0800
@@ -0,0 +1,61 @@
+/* ===-- int_util.c - Implement internal utilities --------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#include "int_util.h"
+#include "int_lib.h"
+
+/* NOTE: The definitions in this file are declared weak because we clients to be
+ * able to arbitrarily package individual functions into separate .a files. If
+ * we did not declare these weak, some link situations might end up seeing
+ * duplicate strong definitions of the same symbol.
+ *
+ * We can't use this solution for kernel use (which may not support weak), but
+ * currently expect that when built for kernel use all the functionality is
+ * packaged into a single library.
+ */
+
+#ifdef KERNEL_USE
+
+extern void panic(const char *, ...) __attribute__((noreturn));
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+void compilerrt_abort_impl(const char *file, int line, const char *function) {
+  panic("%s:%d: abort in %s", file, line, function);
+}
+
+#elif __APPLE__
+
+/* from libSystem.dylib */
+extern void __assert_rtn(const char *func, const char *file, 
+                     int line, const char * message) __attribute__((noreturn));
+
+#ifndef _WIN32
+__attribute__((weak))
+__attribute__((visibility("hidden")))
+#endif
+void compilerrt_abort_impl(const char *file, int line, const char *function) {
+  __assert_rtn(function, file, line, "libcompiler_rt abort");
+}
+
+#else
+
+/* Get the system definition of abort() */
+#include <stdlib.h>
+
+#ifndef _WIN32
+__attribute__((weak))
+__attribute__((visibility("hidden")))
+#endif
+void compilerrt_abort_impl(const char *file, int line, const char *function) {
+  abort();
+}
+
+#endif
diff -Nur libunwind/src/gcc_personality_v0/int_util.h libunwindn/src/gcc_personality_v0/int_util.h
--- libunwind/src/gcc_personality_v0/int_util.h	1970-01-01 08:00:00.000000000 +0800
+++ libunwindn/src/gcc_personality_v0/int_util.h	2014-06-25 11:47:54.010002060 +0800
@@ -0,0 +1,29 @@
+/* ===-- int_util.h - internal utility functions ----------------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===-----------------------------------------------------------------------===
+ *
+ * This file is not part of the interface of this library.
+ *
+ * This file defines non-inline utilities which are available for use in the
+ * library. The function definitions themselves are all contained in int_util.c
+ * which will always be compiled into any compiler-rt library.
+ *
+ * ===-----------------------------------------------------------------------===
+ */
+
+#ifndef INT_UTIL_H
+#define INT_UTIL_H
+
+/** \brief Trigger a program abort (or panic for kernel code). */
+#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, \
+                                                 __FUNCTION__)
+
+void compilerrt_abort_impl(const char *file, int line,
+                           const char *function) __attribute__((noreturn));
+
+#endif /* INT_UTIL_H */

 

9,其他:

Apple还有自己的Blocks语法实现,以及基于Blocks的GCD(dispatch)等等。以及支持ObjectiveC-2.0语法的gnustep libobjc2运行时库等。

这些内容都可以自行查阅相关文档来尝试,有时间的话再补充吧。

Avatar_small
说:
2014年9月11日 14:35

好像 if (D.CCCIsCXX()) 这一行应该删除?
if (StaticLibgcc || isAndroid) {
if (D.CCCIsCXX())
- CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_fnolibgcc)) {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lunwind");
+ CmdArgs.push_back("--no-as-needed");
+ } else
+ CmdArgs.push_back("-lgcc");

Avatar_small
babysitting services 说:
2019年9月24日 15:45

Switching is traumatic and anything you can use to delegate a number that to-do list can certainly make things lots of easier. If it’s a person's old site, your innovative one and also both, we gives your home the latest and healthy and balanced clean with these moving cleaning up service for you to focus traveling. You continue to keep packing plus planning when we deal with the housekeeping.

Avatar_small
monthly maid service 说:
2021年9月07日 17:37

A good deal here can be to not the beginning the glass as well as dead removing all the hard fluids stain. Next you must have a fabulous window wash wand or possibly sponge along with squeegee to clean out the magnifying glaas. In order to clean out the time frame correctly have a very bucket and additionally apply a useful squirt about Dawn dishwash cleaning soap into apprx. 2-3 gallons about water. When you start to sparkling the really difficult water marks dip any wand throughout the cleaning formula and put it to all the glass while the water positions are.

Avatar_small
monthly maid service 说:
2021年9月08日 16:31

Also you can scroll down to check out reviews with particular windows cleaners by Yahoo opinions and location search facts. "Angies List" is additionally a great destination to find information on reputable corporations and purchaser testimonials. Don't hesitate to ask ones neighbors often. You will likely be surprised the best way many persons use products and services and referral marketing is always the most beneficial reference.


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter