diff options
Diffstat (limited to 'content/bootstrapGcc')
-rw-r--r-- | content/bootstrapGcc/00_intro.md | 133 | ||||
-rw-r--r-- | content/bootstrapGcc/01_internals.md | 621 | ||||
-rw-r--r-- | content/bootstrapGcc/02_elf.md | 595 | ||||
-rw-r--r-- | content/bootstrapGcc/NGIAssure.svg | 1 | ||||
-rw-r--r-- | content/bootstrapGcc/nlnet.svg | 34 |
5 files changed, 1384 insertions, 0 deletions
diff --git a/content/bootstrapGcc/00_intro.md b/content/bootstrapGcc/00_intro.md new file mode 100644 index 0000000..e3570ad --- /dev/null +++ b/content/bootstrapGcc/00_intro.md @@ -0,0 +1,133 @@ +Title: Intro to GCC bootstrap in RISC-V +Date: 2022-02-14 +Category: +Tags: Bootstrapping GCC in RISC-V +Slug: bootstrapGcc0 +Lang: en +Summary: + Introduction to my new adventure bootstrapping GCC for RISC-V. Why, how, + and who is going to pay for it. + +You probably already know about how I spent more than a year having fun with +RISC-V and software bootstrapping from source. + +As some may know from my [FOSDEM talk][fosdem22], [NLNet / NGI-Assure put the +funds][nlnet] to make me spend more time on this for this year and I decided +to work on GCC's bootstrapping process for RISC-V. + +[nlnet]: https://nlnet.nl/project/GNUMes-RISCV/ +[fosdem22]: https://fosdem.org/2022/schedule/event/riscvadventures/ + +### Why GCC + +GCC is probably the most used compiler collection, period. With GCC we can +compile the world and have a proper distribution directly from source, but who +compiles the compiler?[^1] + +[^1]: *wHo wATcHes tHE wAtchMEN?* + +Well, someone has to. + +### The bootstrap + +Bootstrapping a compiler with a long history like GCC for a new architecture +like RISC-V involves some complications, starting on the fact that the first +version of GCC that supports RISC-V needs a C++98 capable compiler in order to +build. C++98 is a really complex standard, so there's no way we can bootstrap a +C++98 compiler at the moment for RISC-V. The easiest way we can think of at +this point is to use an older version of GCC for that, one of those that are +able to build C++98 programs but they only require a C compiler to build. Older +versions of GCC, of course, don't have RISC-V support so... We need a +*backport*[^2]. + +[^2]: Insert "Back to the Future" music here. + +So that's what I'm doing right now. I'm taking an old version of GCC that only +depends on C89 and is able to compile C++98 code and I'm porting it to RISC-V +so we can build newer GCCs with it. + +Only needing C to compile it's a huge improvement because there are *Tiny C +Compilers* out there that can compile C to RISC-V, and those are written using +simple C that we can bootstrap with simpler tools of a more civilized world. + +In summary: + +- C++98 is too complex, but C89 is fine. +- GCC is the problem and also the solution. + +### What about GNU Mes? + +When *we*[^3] started with this effort we wanted to prepare GNU Mes, a small C +compiler that is able to compile a *Tiny C Compiler*, to work with RISC-V so we +could start to work in this bootstrap process from the bottom. + +[^3]: "*We*" means I shared my thoughts and plans with other people who have a + much better understanding of this than myself. + +Some random events, like someone else working on that part, made us rethink our +strategy so we decided to start from the top and try to combine both efforts at +the end. We share the same goal: full source bootstrap for RISC-V. + +### Tiny C Compilers? + +There are many small C compilers out there that are written in simple C and are +able to compile an old GCC that is written in C. Our favorite is TinyCC (Tiny C +Compiler). + +[^4]: But there are some others that are really interesting (see +[cproc](https://sr.ht/~mcf/cproc/), for example) + +GNU Mes is able to build a patched version of TinyCC, which already supports +RISC-V (RV64 only), and we can use that TinyCC to compile the GCC version I'm +backporting. + +We'd probably need to patch some things in both projects to make everything +work smoothly but that's also included in the project plan. + +### Binutils + +Binutils is also a problem mostly because GCC, as we will talk about in the +future, does not compile to binary directly. GCC generates assembly code and +coordinates calls to `as` and `ld` (the GNU Assembler and Linker) to generate +the final binaries. Thankfully, TinyCC can act as an assembler and a linker, +and there's also the chance to compile a modern binutils version because it is +written in C. + +In any case, the binary file generation and support must be taken in account, +because GCC is not the only actor in this film and RISC-V has some weird things +on the assembly and the binaries that have to be supported correctly. + +### Conclusion + +This is a very interesting project, where I need to dig in **BIG** stuff, which +is cool, but also has a huge level of uncertainty, which scares the hell out of +me. I hope everything goes well... + +In any case, I'll share all I learn here in the blog and I keep you all posted +with the news we have. + +That's all for this time. If you have any question or comment or want to share +your thoughts and feelings with me[^5] you can find my +[contact information here](https://ekaitz.elenq.tech/pages/about.html). + +[^5]: Or even hire me for some freelance IT stuff 🤓 + +--- + +> PS: Big up to NlNet / NGI-Assure for the money. + +<style> +.container{ + display: flex; + flex-flow: row wrap; + justify-content: center; + gap: 40px; +} +.no-side-margin{ + margin: 0px; +} +</style> +<div class="container"> +<img class="no-side-margin" src="{attach}/bootstrapGcc/nlnet.svg" width=200px> +<img class="no-side-margin" src="{attach}/bootstrapGcc/NGIAssure.svg" width=200px> +</div> diff --git a/content/bootstrapGcc/01_internals.md b/content/bootstrapGcc/01_internals.md new file mode 100644 index 0000000..a6009e1 --- /dev/null +++ b/content/bootstrapGcc/01_internals.md @@ -0,0 +1,621 @@ +Title: GCC internals — From a porting perspective +Date: 2022-03-08 +Category: +Tags: Bootstrapping GCC in RISC-V +Slug: bootstrapGcc1 +Lang: en +Summary: + Deep diving into GCC's internals from the perspective of someone who + wants to port GCC for a new architecture. + + +In the [previous post]({filename}00_intro.md) of the +[series]({tag}Bootstrapping GCC in RISC-V) the problem of the GCC bootstrapping +was introduced. In this post we'll describe how GCC works, from the +perspective of someone who wants to port it so we understand what's the job we +have to do. + +1. [Disclaimer](#disclaimer) +2. [Overview](#intro) + 1. [The compiler generation framework](#cgf) + 2. [GCC as a coordinator](#gcc-coordinator) +3. [Source code parsing](#parsing) + 1. [GENERIC](#generic) +4. [GIMPLE](#gimple) +5. [Register Transfer Language](#rtl) + 1. [Target-dependent code](#target-dependent) + 2. [Machine description files](#md) + 1. [Machine modes](#mm) + 2. [RTL Templates](#rtl-templates) + 3. [Target description macros and functions](#target-desc) +6. [Assembly code generation](#assembly) +7. [Summary](#summary) +8. [My job in the backport](#job) +9. [Last words](#last) +10. [Learn more](#more) + +### Disclaimer {#disclaimer} + +- This post may be only valid for old GCC versions, like 4.something, because + that's the one I'm interested in. More recent versions may have different + details, but I don't expect them to be very different to what is described + here. More specifically: I'm working on GCC 4.6.4, and the first GCC with + RISC-V support is GCC 7.0.0. +- This post will focus on how GCC compiles C programs because that's the part + we care about. Some other languages have differences on how they are treated + but that's not very relevant for us, as it has no implications on the + *back-end*. + +Both of these points will get clearer later. + +### Overview {#intro} + +GCC is structured as a pipeline of several steps that run one after the other. + +1. Source code parsing +2. GIMPLE IR generation (target-independent) +3. Some GIMPLE tree optimizations +4. RTL IR generation (target-dependent) +5. RTL optimizer +6. Assembly code generator + +Before starting to analyze each of the steps independently there are a couple +of things to clarify. + +#### The Compiler Generation Framework {#cfg} + +An important point to note is GCC is a **compiler collection** meaning that it +is able to compile code from many high level languages (HLL) and for many +different targets. This has implications on how some steps are mapped to GCC's +source code. + +The most important thing of all this is to differentiate between GCC's code and +an actual `gcc` executable. The key point here is that GCC's codebase includes +what is called CGF (Compiler Generator Framework) that can generate `gcc` +executables from GCC's code. The CGF generates `gcc` executables according to +the input (target machine, host machine...) we give it, but the generated `gcc` +executables may differ one from another even if they were generated from the +same codebase. + +Any `gcc` executable is able to compile any input HLL[^language] (C, C++, +Objective-C, Ada, Fortran and Go[^java]), so GCC's code must include parsers +for each of these languages. + +[^language]: When calling `gcc` you can choose which language you are compiling + using `-x language` option or you can let `gcc` guess from the extension. + +[^java]: And also Java in the past! + +On the other hand, `gcc` executables are only able to generate code for one +target (x86, MIPS, ARM, *RISC-V*...), that must be chosen when GCC is compiled. +In order to make the porting efforts easier, GCC has a set of tools that +generate the target-dependent code from some configuration files called Machine +Descriptions (MD). + +Putting all this together, source code parsing and AST generation depend on the +input HLL, and the code that runs for each HLL is **selected** when `gcc` runs +(*steps 1*). The intermediate representation, GIMPLE, is target-independent so +everything related with that is **copied** inside the final `gcc` executable +(*steps 2 and 3*). The RTL (Register Transfer Language) representation and +assembly code generation are target-dependent and the code related to that is +**generated** from MD files when GCC is compiled (*steps 4, 5 and +6*)[^rtl-opt]. + +[^rtl-opt]: The RTL optimizer contains many steps, most of them being target + independent. That doesn't really matter here, but those are not generated but + copied from GCC's source, as GIMPLE is. + +This all means if we want to be able to read the source code of GCC we have to +have clear in mind how the source code maps to the actual executable, i.e. if +we generate a `gcc` executable for **x86** it won't contain the code for other +architectures and **it won't even check if it was correctly programmed**, +because it's not going to compile it. + + +#### GCC as a coordinator {#gcc-coordinator} + +Many GCC users or C programmers (or me, not that long ago) might think there is +something missing on the list of steps we recently reviewed. The normal usecase +for calling `gcc` like + +``` bash +$ gcc -o helloworld helloworld.c +``` + +does several steps internally that we need to separate: + +1. Preprocessing: the resolution of preprocessor macros like `#define` and + stuff like that. +2. Compiling to assembly: the generation of assembly code files per compilation + unit (a file that is the output of the preprocessor). +3. Assembly: the conversion from an assembly file to ELF object file. +4. Linking: the executable or library generation from the ELF object files + created in the previous step. + +The reality is there's more than one program involved here and `gcc` is just a +coordinator that makes other programs run if needed. + +The preprocessor is called `cpp` and it is generated from the GCC codebase. The +compiler is `gcc` itself but the assembler and the linker are generally +obtained from GNU Binutils' `as` and `ld` respectively. + +So, one of the most important things to understand is GCC only generates +assembly, but it looks like it doesn't[^tinycc-asm]. + +This means we need a proper support for our architecture on the assembler and +the linker too. But we'll keep that story for another day[^post-long]. + +[^tinycc-asm]: Other compilers have different approaches for this. For example, + TinyCC generates machine code directly, without the intermediate assembly + file generation step, and is also able to link the files by itself. + +[^post-long]: This post is already long enough and we only made the + introduction. + +--- + +### Souce code parsing {#parsing} + +> HLL dependent. Generates appropriate IR + +So the first step of the compiler is to process the input text and convert it +to the appropriate Intermediate Representation. The most used intermediate +representation is GENERIC, that was designed for C but fits other procedural +languages pretty well[^fortran]. + +[^fortran]: The case of FORTRAN is a little bit weird, as it generates its own + representation that is later converted to GENERIC, we don't really care about + this at this point. + +This parsing process not really relevant for us, as we want to add a new +target, but it's interesting to note because it gives shape to the codebase. +GCC splits the code for the different input languages in folders named like: +`gcc/$LANGUAGE`. + +#### GENERIC {#generic} + +GENERIC is just a representation, we don't need to care that much about it but +a word is not going to hurt anyone. GENERIC is a tree representation: a set of +nodes with some extra common information. Those nodes can be read at +`gcc/tree.def`. + +A simple example of this could be a function declaration, that would take the +a node of type `FUNCTION_DECL` that has some sub-nodes: one for the return +type, another for the body of the function and another for the arguments of the +function. + +It's a simple AST you could come up with yourselves, except the fact that it is +pretty complex. 😅 + +### GIMPLE {#gimple} + +> HLL- and Target- independent representation + +The next step is called *Gimplification* (see `gimplify.c`), the process of +converting to GIMPLE. Normally, representing the AST as GIMPLE is too complex +to be done in one step, so the GENERIC (+ some extensions) is used as a +previous step that is easier to create. + +GIMPLE is the central internal representation of GCC. It's target-independent +and High-Level-Language-independent. At this point some optimizations can be +applied, those related with the structure of the source code, like loop +unfolding or dead code elimination. + +From the porting perspective, this representation is important, as it's the +border line between the front-end and the back-end, and we are interested in +the latter. A really interesting part is to understand is how is this converted +to the next representation, RTL. + +### Register Transfer Language (RTL) {#rtl} + +> Target-dependent low level representation + +The next part of the compiler work is done using the RTL intermediate +representation. The RTL representation is based on LISP, so we have a reason to +love it, and it serves two purposes: + +1. Specify target properties via the Machine Descriptor files. These Machine + Descriptor files are text files that look like LISP and are processed at + compilation time. +2. Represent a compilation. Meaning that the RTL is also an intermediate + representation, a low-level one, that represents sets of instructions. + +GCC does not make any distinction between the first and the second purpose, +calling both RTL, but there some difference on the purpose and the shape of the +RTL. RTL has both, an internal form represented by structures (case 2) and an +external form represented as a text file (case 1). + +The RTL is formed by a set of objects: expression, integers, wide integers, +strings or vectors. In the textual form they are represented like in LISP, +using double quotes for strings, brackets for vectors... and a lot of +parenthesis. The internal representation you can imagine, structures for +expressions, integer types for integers, `char*` for strings, etc. + +The most interesting RTL objects are expressions, aka RTX, that are just a name +(an expression code) plus the amount of possible arguments. + +This is how a piece of RTL may look, it represents an instruction that sets the +register 0 to the result of the addition of the register 1 and the constant +integer 10 (see `rtl.def` for more information): + +``` lisp +(set (reg 0) + (plus (reg 1) + (const_int 10))) +``` + +In the example the only things that are not expressions are the numbers (0, 1 +and 10), all the rest you can find in `rtl.def` and see what they mean. + +From GIMPLE, there are two steps left to reach our target, assembly code, and +both involve RTL. The first maps the GIMPLE nodes to pattern names in a +target-independent way, generating a list of RTL `insn`s. The second matches +those `insn` lists to RTL templates described in Machine Description files and +uses those matches to generate the final assembly code. + +Those `insn`s are objects that represent code in RTL. Each function is +described with a doubly-linked list of `insn`s. You can think about them as +*instructions* in the RTL world. + +In the first step, the RTL `insn` generation step, only the names matter (and +they are hardcoded in the compiler), while in the second the structure of the +`insn` is going to be analyzed as we'll see later. + +#### Target-dependent code {#target-dependent} + +As we previously said, target-dependent steps are generated at compile time and +then inserted in the final `gcc` executable. All this code is located in one +folder per target, under `gcc/config/$TARGET`, so the CFG is able to load the +target we choose at compile time (using `--target=`) and insert that in the +final executable. + +That is done in different ways depending on the type of file we are working +with: Machine Description files are processed by the programs (`gencodes`, +`gentags`...) that generate C code files from them, while target description +macros and functions, which are C files, are inserted in the building process +as any other C file. + +I'd like to insist here on the fact that the `--target` is the only one to be +processed and loaded and the other possible targets are going to be ignored. +The build process is not going to complain if a target is broken or anything +like that if it isn't the target we chose. It just doesn't care. + +#### Machine Description files {#md} + +Machine Description files (`.md` extension) let us define `insn` patterns, +which are incomplete RTL expressions that can be matched against the `insn` +list generated from the GIMPLE, `attributes` and other interesting things we +may not try to decipher here. + +`define_insn` is a RTX we can use to define new `insn` patterns. It receives +four or five operands: + +1. An optional name. It's going to be used to match against GIMPLE. +2. An RTL template. A vector of *incomplete* RTL expressions which describe how + should the instruction look like. *Incomplete* in this context means it uses + expressions like `match_operand` or `match_operator` which are designed to + match against the RTL `insn` list and see if they are compatible or not. +3. A condition. A final condition to say if the `insn` matches this pattern or + not. +4. An output template. A string that contains the output assembly code for this + `insn`. The string can contain special characters like `%` to define where + should the arguments be inserted. If the output is very complex we can write + C code on this field too. +5. An optional list of attributes. + +This is an actual example from the RISC-V code we are backporting: + +``` lisp +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "register_operand" "r,r") + (match_operand:DI 2 "arith_operand" "r,I")))] + "TARGET_64BIT" + "add\t%0,%1,%2" + [(set_attr "type" "arith") + (set_attr "mode" "DI")]) +``` + +You can see the name `adddi3` is something like: `add` + `di` + `3`. This means +it's the `add` instruction with the `di` mode and `3` input arguments. That's +the way things are named. + +Next block is a vector with the RTL template. If you try to ignore +`match_operand` expressions you can see the template is not very different to +the RTL example we gave before. In this case it's something like: + +``` lisp +(set (reg 0) + (plus (reg 1) + (reg 2))) +``` + +It's basically storing in the first register the result of the addition of the +other two. + +The next field is the condition. In this case it needs to have `TARGET_64BIT` +defined in order to work because the machine mode is `DI` (we'll explain that +soon). + +The output code is simple, just a RISC-V `add` instruction: + +``` asm +add %0,%1,%2 +``` + +Where `%N` is going to be replaced by the register numbers used as arguments +for this instruction. + +The last field are the attributes, which can be used to define the instruction +size and other kind of things. We are not going to focus on them today. + +##### Machine modes {#mm} + +Machine modes are a way to describe the size of a data object and its +representation. + +- QI: quarter integer +- HI: half integer +- SI: single integer +- DI: double integer +- SF: single floating +- DF: double floating + +And so on. + +The standard `insn` names include machine modes to describe what kind of +instruction they are. The example above is `addddi3`, meaning it uses `di` +machine mode: double integer. That's why it needs the target to be a 64 bit +RISC-V machine. + +Machine modes also appear in some RTL expressions like `plus` or +`match_operand` meaning that they operate in that machine mode, that is, with +that data size and representation. For example `(plus:SI ...)`. + +##### RTL Templates {#rtl-templates} + +`match_*` expressions are what make RTL expressions *incomplete*, because they +are designed to be compared against the `insn` list that comes from the +previous step. + +In the example above we had: + +``` lisp +(set (match_operand:DI 0 "register_operand" "=r,r") + (plus:DI (match_operand:DI 1 "register_operand" "r,r") + (match_operand:DI 2 "arith_operand" "r,I"))) +``` + +`(match_operand N predicate constraint)` is a placeholder for an operand number +`N` of the `insn`. When the `insn` is constructed, the `match_operand` will be +replaced by the corresponding operand of the `insn`. When the template is +trying to match an `insn` the `match_operand` forces the operand number `N` to +match the `predicate` in order to make the `insn` match the template. +The `match_*` expressions are what defines how `insn`s should be. + +The `predicate` is a function name to be called. The function receives two +input arguments: an expression and a machine mode. If the function returns `0` +the function does not match. + +`predicate`s can also be combined in Machine Description files like this: + +``` lisp +(define_predicate "arith_operand" + (ior (match_operand 0 "const_arith_operand") + (match_operand 0 "register_operand"))) +``` + +So the `arith_operand` shown in the example above can be a +`const_arith_operand` *or* (that's what `ior` means) a `register_operand`. +They can be more complex but this is more than enough to understand how they +are built. In the end, they always check against C functions, but you can +combine them with the convenience of the Machine Description files. + +The `constraint` allows to fine-tune the matching. They define if the argument +is in a register or the memory and stuff like that. `r`, for example, means the +operand comes from a register. + + + +There are other matching expressions too, but `match_operand` is the most used +one and it's the one that explains this concept of *incomplete* expressions the +best. + + + +#### Target description macros and functions {#target-desc} + +Apart from the machine descriptor files, there are other files involved. For +example, the constraints defined above need to be defined in code somewhere. + +The most important of these are the target description macros and functions, +normally defined in `gcc/config/$TARGET/$TARGET?(.h|.c)`. The `.c` should +initialize the `targetm` variable, which contains all the machine information +relevant to the compiler. It is initialized like this: + +``` c +struct gcc_target targetm = TARGET_INITIALIZER; +``` + +That `TARGET_INITIALIZER` is a huge macro, defined in `gcc/target.h`, that +initializes the `targetm` structure. This macro is split in smaller macros with +reasonable defaults that may be overwritten by pieces. Each target should have +a file that includes both `target.h` and `target-def.h` and overwrites any +inappropriate default by redefining new macros and ends with the initialization +line we just introduced. This is normally done in +`gcc/config/$TARGET/$TARGET.c`, while the `.h` is normally used to define some +macros that are needed in the `.c` file. + +As a reference, the RISC-V code we need to backport (see +`gcc/config/riscv/riscv.c`) uses the file to introduce the amount of registers, +the type, the size, and that kind of things, and many others. + +All this information contained in `targetm` is used by the compiler to decide +how registers have to be allocated, which ones have preference, the cost of +them, and many other things. + +### Assembly code generation {#assembly} + +Having the previous step clear is enough to understand how does the assembly +generation work. Each of the `insn`s in the list obtained from GIMPLE is going +to be compared against the RTL templates and the best match is going to be +chosen. Once the match is chosen, the corresponding assembly is going to be +generated from the corresponding field of the `define_insn` RTL expression. + +As simple as that, but also that complex. + +Why do I say it's complex? Because many things have to be considered and GCC +does consider them. Each instruction has a size, that has to be considered to +calculate addresses, but also they have some execution time associated and GCC +calculates the best matches to make the final assembly file as optimum as +possible. + +The RTL step has a lot of optimization passes, too. It's a complex step but +it's not really important for us because we just need to make a temporary +compiler that lets us compile a better one. It doesn't really matter if it's +not perfect, at least at this point. + + +### Summary {#summary} + +So, in summary, the process is the following: + +1. The HLL language is parsed to a tree, normally GENERIC. +2. GENERIC is converted to GIMPLE. +3. GIMPLE optimizations are applied. +4. GIMPLE is matched to a `insn` list using pattern names. +6. The `insn` list is matched against the RTL templates defined in the Machine + Description files. +7. RTL optimizations are applied. +8. The matches convert the RTL to assembly code also taking in account the + information obtained from the target definition macros and functions. + +From our perspective, the most important things to remember are these: + +- The front-end is not very relevant for us, from the parsing to GIMPLE we can + ignore for the moment. +- RTL step is pretty complex, and the GIMPLE->RTL conversion is too. +- GCC is a compiler collection that has a very powerful compilation process, + the Compiler Generator Framework (CFG), in order to modularize the code and + make it easier to port. +- The machine description files and the target definition macros and functions + are designed to make the porting process simpler. Those are the only files we + need to touch. + +--- + +<div style=" + text-align: center; + font-size: smaller; + padding-left: 3em; + padding-right: 3em; + padding-top: 1em; + padding-bottom: 1em; + border-top: 1px solid var(--border-color); + border-bottom: 1px solid var(--border-color)"> +If you like my job here, consider hiring <a href="https://elenq.tech">ElenQ +Technology</a>. <br> Even if I'm busy with this, I still have some time slots +available. +</div> + +--- + + +### My job in the backport {#job} + +With all the process more or less clear, we can be more specific on the job I +need to do. I share some specifics in this section, so if you like reading code +you are going to have some fun[^examples]. + +[^examples]: I'll link to some examples of the code on RISC-V's GitHub account. + This code is already merged in GCC. + +First, I need to make sure all the used RTL expressions are compatible with the +old version of the compiler. If they are not, I have to translate them to the +old way to make them. Some examples of this are iterators like +[`(define_int_iterator ...)`][int-iterator] which is not available in old GCC +versions, so I need to unfold a couple of loops by hand and make them only use +the old constructs. + +[int-iterator]: https://github.com/riscv-collab/riscv-gcc/blob/ca312387ab141060c20c388d83d6fc4b2099af1d/gcc/config/riscv/riscv.md?plain=1#L342 + +Second, I need to convert the target description macros and functions to the +old internal C-based API instead of the more [modern C++-based one][c++api], as +the recent port uses. These changes involve many layers and I didn't yet +analyze this in detail. They can be simple like converting from `rtx_insn` +class to `rtx`, the older way to do this. But they can also be complex, like +removing the 40% of the `#include` directives from `riscv.c`, which has many +that were not available in the past. It's going to be a lot of fun I predict. + +[c++api]: https://github.com/riscv-collab/riscv-gcc/blob/ca312387ab141060c20c388d83d6fc4b2099af1d/gcc/config/riscv/riscv.c + +Third, as this whole compilation process is complex, I decided to make it as +accessible as possible, so other people can audit and replicate my work. For +that I'm using Guix, my package manager of choice. I added a [`guix.scm`][guix] +and [`channels.scm`][channels] file to the repository so my work can be +replicated precisely by myself in the future, or by others[^github]. + +The Guix package also provides a better interaction with the building process +of GCC, letting us replace inputs in a very simple way. I'm thinking about the +next steps of the project here, when we need to compile my backported compiler +with TinyCC, test if it works and then patch TinyCC until it does. Having the +`guix.scm` file makes it easy to replace the current compiler with a patched +TinyCC and ensures nothing is interfering in the compilation process because +the compilation is done in an isolated container. + +[^github]: I'm hosting this on GitHub at the moment because the repository is + huge. I'll probably move all this to my server and edit the post after that. + +[guix]: https://github.com/ekaitz-zarraga/gcc/blob/guix_package/guix.scm +[channels]: https://github.com/ekaitz-zarraga/gcc/blob/guix_package/channels.scm + +That's mostly the job I need to do in the backport. + +Something to keep in mind is that we don't need to make it perfect, we just +need it to work. The backported GCC is not going to be used as a production +compiler, but just as a bridge with the next GCC version, so **there's only one +program it needs to be able to compile correctly: GCC 7**. Once we make the +bridge with the next version, we can use that to compile anything we want. + + +### Last words + +I know this post is long, and the lack proper diagrams make everything a little +bit hard to understand. That's exactly how I felt reading about GCC, but the +difference was I had to read some documentation that is... About 100 times +longer than this post (see [Learn more](#more) below). Not that bad after all. + +There are many things I decided to leave out, like peephole optimizations, +instruction attributes, and some other constructs that are not that important +from my perspective. You may want to make your research on those on your own. + +In any case, if you have any question you can always contact me[^contact] and +ask me any questions you have or send me some words of support. + +In the next post I'll describe a little bit about ELF, the executable and +linkable format, just the bare minimum to understand the format, as it will be +relevant for us in the future. And you might be thinking, why is it relevant if +GCC compiles to assembly? Well, that's one of the questions that we will be +answering in the next post. + +Now I leave you with a couple of interesting links on the next section. + +Good luck with your ports! + + +[^contact]: You can find my contact info in the [About + page](/pages/about.html). + + + +### Learn more {#more} + +- [The GCC internals documentation](https://gcc.gnu.org/onlinedocs/gccint/): if + you are interested on my work you should read an older version of the + documentation. See [Disclaimer](#disclaimer). +- [The GCC source code](https://gcc.gnu.org/git.html): of course, this has + everything you need to understand GCC, but the problem is that GCC is a huge + codebase, you probably need to spend months reading it in order to understand + everything. That's why I think posts like this one are interesting, they help + you focus on the parts you are interested in. + diff --git a/content/bootstrapGcc/02_elf.md b/content/bootstrapGcc/02_elf.md new file mode 100644 index 0000000..c684c63 --- /dev/null +++ b/content/bootstrapGcc/02_elf.md @@ -0,0 +1,595 @@ +Title: ELF format — why not? +Date: 2022-03-14 +Category: +Tags: Bootstrapping GCC in RISC-V +Slug: bootstrapGcc2 +Lang: en +Summary: + Some introduction to ELF as we'll need to deal with this in the future. + +In the [previous post]({filename}01_internals.md) of the +[series]({tag}Bootstrapping GCC in RISC-V) we introduced GCC and how it +generates assembly code and we left a question unanswered: *"Why is learning +about ELF interesting if GCC generates assembly?"*. In this post we are going +to answer that question (not interesting) and maybe understand the very basics +of ELF file format (more interesting). + + +### What's ELF + +ELF is a file format with two main goals: + +- Represent an executable file +- Represent a linkable file + +Apart from that, ELF can also represent core dumps, but if you think about that +all of the possible options have something in common: they represent contents +on the memory. We can simply say ELF is a file format that acts as a picture of +the state of the memory. In the case of the executables, the state will be +loaded from the file, but in the case of the core dumps the state is obtained +from the memory and dumped in a file. + +Linkable files are those files that can be combined with others to generate +executables or shared objects, so they can also fit that definition because +they are going to end up in the memory anyway. + +For efficiency reasons, the ELF format has two separate views of the same +contents: + +- The **Linking** view is based on sections and needs a *section header*. +- The **Executable** view is based on segments and needs a *program header*. + +#### ELF header + +The ELF header is the only thing that has a fixed position in the file, at the +beginning. The ELF header has information that defines how to identify the +file, the machine, the endianness and that sort of things, but it also says +where are the headers located and identifies the size of their entries and +their entry count. + +It's not that interesting, honestly. The most important thing is it points to +the descriptions to both of the views (the headers) so we can check them. + +#### Linking view + +Based on sections, the linking view is the most detailed view of the file and +it defines how the file should be linked with others in order to create an +executable file. + +Sections, the basic unit of the linking view, are consecutive sequences of +bytes that do not overlap. + +There are [different types of sections according to their possible contents and +meaning](https://refspecs.linuxfoundation.org/LSB_3.0.0/LSB-PDA/LSB-PDA.junk/sections.html), +the most interesting are: + +- `SYMTAB` and `DYNSYM` that hold a symbol table. The `DYNSYM` is for dynamic + linking symbols, while `SYMTAB` normally is used for static linking but may + contain both. +- `STRTAB` holds a string table. +- `RELA` contains relocation entries with addends and `REL` contains + relocations without addends. +- `NOTE` section contains some information of the file. +- `HASH` contains a symbol hash table, necessary for dynamic linking. +- `DYNAMIC` for dynamic linking information. + +Each section has also a `name`, an `address` if it is supposed to appear in the +memory of running process, an `offset` that defines where in the file do the +section's contents appear, a `size`, and some extra data fields that all +together form a section header entry. + +The section header entries are all located where the ELF header says, one after +the other (like a C array of structures), so the programs just need to access +that position in the file and read all the headers in a row. The contents of +the sections are located throughout the file, where the section headers point. + +##### String section + +The string section (`STRTAB`) is one of the simplest. It contains all the +strings of the file: the section and symbol names. It's simply a set of null +terminated strings, written one after the other (it also starts with a null +character but whatever). + +Anywhere in the file where we are supposed to get an string what we get is an +index that points to the first position in this section to read from. We should +read from that until we reach a null character. For example in the following +string section: + +``` + \0 h e l l o \0 n a m e \0 +``` + +If a name of a section says `1`, the actual name of the section is `hello` +and if it says `7` it would be `name`. Also, if it says `9` it would be `me`, +this trick could be used too. + +##### Symbol table + +The symbol table contains information needed to locate and relocate a program's +symbolic definitions and references. The symbol table is formed as an array of +symbol elements that are defined with a `name`, obviously a `value`, their +`size`, some extra `info`, the index of the section header they relate to +(`shndx`) and some `other` stuff. + +The `info` field manages symbol's type (`OBJECT` for data, `FUNC` for +function...) and binding attributes, which define the linking visibility and +behavior of the symbol (local vs global...). + +The `value` can be interpreted in several ways too, depending on the type of +the symbol you are dealing with. But that's not really relevant for us at the +moment. + +##### Relocation + +According to the ELF documentation I got from somewhere I don't really +remember: + +> The relocation is the process of connecting symbolic references with symbolic +> definitions. + +I hope it's more explanatory for you than what it is to me, but I don't have a +clue of what that is supposed to mean. The +[Wikipedia](https://en.wikipedia.org/wiki/Relocation_(computing)) does a **much +better** job in the specifics right here: + +> Relocation is the process of assigning load addresses for position-dependent +> code and data of a program and adjusting the code and data to reflect the +> assigned addresses. + +If this doesn't really help, you have a really good example later, but we can +basically say that it's a way to adjust the code to point to the correct +addresses, at linking or loading, or even execution, time. + +ELF files have, as we said, sections that let us define relocations. These will +point to some parts of the file and tell the linker or the loader that that +positions of the file must be reprocessed. + +There are two types of relocation sections and in both of them the relocation +section is an array of entries where each of them represents one relocation. +In the simple one (`REL`) each relocation only contains an `offset` and an +`info` word, which also includes the type of relocation to apply. The more +complex one (`RELA`) is mostly the same but it includes an `addend` which +includes a constant value to use in calculation of the relocation. + +The calculus of the final addresses are specific to the ISA and the relocation +type, because processors have different instruction formats and different ways +to pack addresses in instructions. RISC-V has no way to pack a full address +inside of an instruction, while x86 does, so they have to patch the +instructions in a different way. + + +##### Special sections + +Some sections have a special treatment according to their name, normally the +ones that start with a dot. These you might have found in the past in assembly +files, defined like `.data` (for data), `.rodata` (for read only data) or +`.text` (for code). + +These are interesting to have in mind because they appear the same way they do +in assembly, and we are going to disassemble some of them and play around with +them. + +Other special sections like `.got` or `.dynamic` don't appear in assembly but +they have a strong meaning in the resulting file, we are not going to deal with +those today because we want to finish this post someday. If you need to deal +with those I recommend you to read ELF's documentation on special sections and +the loading process. + + +#### Executable view + +The executable view is another way to access the same contents, but with a +different perspective. It's based on *segments* rather than *sections*. +Segments are also pieces of the file, as sections are, but segments can contain +one or more sections. + +Like in the linking view, the base unit, sections for the linking view but for +segments for the executable view, are described in a header. The header of the +executable view is called program header and it is, like the section header, a +bunch of structures piled together, each describing one of the segments. + +The program header describes the position and size in the file of each of the +segments but also some important information about them: how they are supposed +to be loaded in the memory and where (virtual address and physical address), +the type of the segment, and some info more. + +The most interesting segment types are the following: + +- `LOAD` is used for loadable segments, with the other fields of the segment + the position and the size this segment will have in memory are described. +- `DYNAMIC` are segments that have some dynamic linking information. It has to + contain the `.dynamic` section. +- `INTERP` gives the location and size of a null-terminated path name to invoke + as an *interpreter*. Interpreter in this context usually means a dynamic + linker, which will be called instead of loading this file to memory and the + dynamic linker will be the one that will load the parts of the file it + considers. + +You can see how segments are interesting for loading the file in the memory, +that is, they are mostly interesting for executable files or shared objects. + +#### Segments vs Sections + +If you want to have a clear idea about the difference between segments and +sections, you can consider a file with multiple sections: `.text`, `.rodata` +and `.data`. + +A file that contains those sections can be understood from a linking +perspective as a file that has some code (`.text`), read-only data (`.rodata`) +and read-write data (`.data`). Each of those parts must be managed in a +different way by the linker, but the reality is that the program loader doesn't +really care about some of the differences of them. + +The code and the read-only data are loaded in the memory in the same way, with +read and execute permission but no write permission, so the executable view can +put both sections in the same segment, and make the loader's life easier. + +Also, the linker doesn't really care about how is the memory loaded so the +section header does not hold that information. It does care about the section's +goals though, as it will need to put them together in order during the linking. +On the other hand, the loader is not really interested on what's the goal of +the contents of the file but only on what to do with those contents, so it only +has that information. + + +### So, why do we need to learn it? + +We don't really need to learn it very deeply, just learn how it works in a +high-level way and make sure we are able to read it with the tools we have +available. The good news for you is if the reasons I give you are not good +enough it doesn't really matter because you already learned[^gotcha]. Continue +reading and you'll realize how much you understand now. + +[^gotcha]: Ha! Gotcha! + +First, let me tell you a personal story. I have previous experience working +with assembly, but only in small devices that have two memories, one for data +and other for code (Hardvard Architecture). In those small devices you often +don't really need to think about how the code and the data is mapped to memory +because your programs are small and the separation is clear. Computers are a +different thing, and I have had issues understanding this whole assembly thing. + +Computers store both code and data in the same memory, the main memory, (Von +Neumann Architecture) and they normally have memory segmentation, pagination, +memory management units and all that kind of stuff, because there are many +processes running and they want to separate one from the other. That forces us +to think about how the code and the data are mapped to the memory. Also, modern +operating systems also use dynamic linkers, which are not available in small +devices, and we need to be able to deal with that amount of complexity. + +ELF allows us to make that all, because it was born for that. ELF is a +distillation of many of the ideas from System V Unix, that include exactly all +I mentioned. It's a great way to understand how memory, linking and processes +work in a *modern* operating system. This is why you need to learn it, at least +a little. It makes you a cultivated person, which is always good[^system-v]. + +[^system-v]: It also makes you understand the complexities of the system so you + can criticize it. Changing the world requires to learn about it first. + +#### The specifics + +As I'm sure you are not satisfied totally with the answer of being a cultivated +person[^some-of-you], let me go for some specifics. + +[^some-of-you]: For those that really are. That's the good attitude in life. + High five. You can read the whole section still, it has interesting points I + think. + +So in this project GCC is not the only software we are dealing with, GNU +Binutils and TinyCC are part of the party too, and I need to make them fit +together in the best way possible. In those I need to make sure the +relocations, formats and other things work properly, following the RISC-V ABI +specification for ELF. That might be a point of failure, so being prepared on a +high-level at least is interesting. + +Of course, GCC's output we need to analyze too, and in order to do that we need +to make sure we know what it means. We already saw that some ELF sections are +directly mentioned in the assembly, so in order to know their meanings ELF is a +good way to understand them. They are really an OS related thing and ELF only +reflects it, but learning them from the ELF perspective makes the path easier +probably. + +Relocations are a huge point in all this mess, because they are machine +specific (instructions are too, but those I expect us to know already), and +they are something I didn't need to research on all the RISC-V adventures I had +last year. I have to do it sometime. + +In general, there are many sharp edges where we can get hurt, so it's better if +we wear gloves. + +### Tools + +For all this process there are a couple of tools that were designed to help. +GNU Binutils has many of them but we are going to focus on two, as they are +more than enough for many usecases: `objdump` and `readelf`. + +The example below uses both of them to analyze a piece of code and its +compilation result. As you'll see, the main problem they have is their output: +it's not always clear, the formatting is a little bit chaotic, it's not +obvious at all to get right and it's really hard to use it procedurally. + +There is a really cool tool you should investigate though, called GNU Poke, +that is designed specifically to fight against those issues. I recommend you to +[take a look to it](https://www.gnu.org/software/poke/). + +### Example + +Starting from a very simple C file we can follow a really interesting process +and understand some of the ELF internals: + +``` c +long global_symbol; + +int main() { + return global_symbol != 0; +} +``` + +We compile it to assembly with: + +``` asdf +$ riscv64-linux-gnu-gcc -S b.c -O0 +``` + +This are the contents of the assembly file: + +``` asm + .file "b.c" + .option pic + .text + .globl global_symbol + .bss + .align 3 + .type global_symbol, @object + .size global_symbol, 8 +global_symbol: + .zero 8 + .text + .align 1 + .globl main + .type main, @function +main: + addi sp,sp,-16 + sd s0,8(sp) + addi s0,sp,16 + lla a5,global_symbol + ld a5,0(a5) + snez a5,a5 + andi a5,a5,0xff + sext.w a5,a5 + mv a0,a5 + ld s0,8(sp) + addi sp,sp,16 + jr ra + .size main, .-main + .ident "GCC: (Debian 10.2.1-6) 10.2.1 20210110" + .section .note.GNU-stack,"",@progbits +``` + +Assemble the file with `as`: + +``` asdf +$ riscv64-linux-gnu-as b.s -o b.o +``` + +And this is what we get in `b.o`. The `.text` section contains the following: + +``` asm +$ riscv64-linux-gnu-objdump --disassemble b.o + +b.o: file format elf64-littleriscv + + +Disassembly of section .text: + +0000000000000000 <main>: + 0: ff010113 addi sp,sp,-16 + 4: 00813423 sd s0,8(sp) + 8: 01010413 addi s0,sp,16 + c: 00000797 auipc a5,0x0 + 10: 00078793 mv a5,a5 + 14: 0007b783 ld a5,0(a5) # c <main+0xc> + 18: 00f037b3 snez a5,a5 + 1c: 0ff7f793 andi a5,a5,255 + 20: 0007879b sext.w a5,a5 + 24: 00078513 mv a0,a5 + 28: 00813403 ld s0,8(sp) + 2c: 01010113 addi sp,sp,16 + 30: 00008067 ret +``` + +### Relocations + +There are some relocations! + +``` asdf +$ riscv64-linux-gnu-objdump b.o -r + +b.o: file format elf64-littleriscv + +RELOCATION RECORDS FOR [.text]: +OFFSET TYPE VALUE +000000000000000c R_RISCV_PCREL_HI20 global_symbol +000000000000000c R_RISCV_RELAX *ABS* +0000000000000010 R_RISCV_PCREL_LO12_I .L0 +0000000000000010 R_RISCV_RELAX *ABS* +``` + +But in order to understand those relocations properly we need to check the +value of the symbols too: + +``` asdf +$ riscv64-linux-gnu-objdump -t b.o + +b.o: file format elf64-littleriscv + +SYMBOL TABLE: +0000000000000000 l df *ABS* 0000000000000000 b.c +0000000000000000 l d .text 0000000000000000 .text +0000000000000000 l d .data 0000000000000000 .data +0000000000000000 l d .bss 0000000000000000 .bss +0000000000000000 l d .note.GNU-stack 0000000000000000 .note.GNU-stack +000000000000000c l .text 0000000000000000 .L0 +0000000000000000 l d .comment 0000000000000000 .comment +0000000000000000 g O .bss 0000000000000008 global_symbol +0000000000000000 g F .text 0000000000000034 main +``` + +If you pay attention to the offsets of those relocations (`0x0c` and `0x10`) +they exactly match the instructions `auipc a5, 0x0` and `mv a5, a5` and those +are expanded from the `lla a5, global_symbol` (load local address) +pseudoinstruction from the assembly. + +The `mv` is not really a `mv`. `mv` is a pseudoinstruction too, that should be +expanded to an `addi a5, a5, 0`. The `objdump` is playing with us, making the +opposite conversion so we can read better but in fact is tricking us. + +The `auipc` + `addi` couple in RISC-V appears pretty often, because it's the +method it has to load addresses in memory. The first instruction, `auipc` adds +a high part of an immediate to the program counter and stores the result in a +register, the `addi` adds then another, in this case low, immediate to the +register i.e. they make a `x[reg] = pc + immediate` operation in two steps: +`x[reg] = pc + hi20(immediate)` followed by `x[reg] = x[reg] + lo12(immediate)`. + +As we have relocations in both `auipc` and `addi` this means their `0` values +(the immediates) are going to be overwritten with something else at linking +time, and there's when RISC-V has something to say. All the relocations we can +see are RISC-V specific, and you can read about them in [RISC-V ABI +Specification](https://github.com/riscv-non-isa/riscv-elf-psabi-doc). + +In our case we have really some simple ones, the easiest to understand (what a +coincidence, huh?): + +> `R_RISCV_PCREL_HI20`: High 20 bits of 32-bit PC-relative reference, +> `%pcrel_hi(symbol)`. The formula is: `S+A-P` [but only obtains the highest 20 +> bits]. + +> `R_RISCV_PCREL_LO12_I`: Low 12 bits of a 32-bit PC-relative, +> `%pcrel_lo(address of %pcrel_hi)`, the addend must be 0. The formula is: +> `S-P` [but it only obtains the lowest 12 bits]. + +Both the `HI20` and the `LO12` have a similar formula, this is the meaning of +the elements on the formula: + +- `S`: Address of the symbol +- `A`: Addend of the relocation +- `P`: Position of the relocation + +If you match their formulas with the description of what we just said about how +do `auipc` + `addi` couples work, you can easily understand the formulas and +their meaning. We are not going to do it, do something yourself! + +The other relocation: + +> `R_RISCV_RELAX`: Instruction can be relaxed, paired with a normal relocation +> at the same address. + +Is an addition our example doesn't use but it could. The `R_RISCV_RELAX` +basically means that if the relocation it points at is not needed it can be +discarded. And when does that happen? Easy, when we can get `global_symbol`'s +address with only one of them, we can remove the other instruction from the +program. + +#### Relocation resolution + +If we link the file and generate an executable, we can see the final value +those zeroes get. + +``` asdf +$ riscv64-linux-gnu-gcc b.o -o b.out +``` +We link it like this because `ld` needs a lot of input fields and we don't want +to set them all by hand, but you can do it with `ld` if you feel like it. + +``` asdf +$ riscv64-linux-gnu-objdump --disassemble b.out +... +00000000000005e4 <main>: + 5e4: ff010113 addi sp,sp,-16 + 5e8: 00813423 sd s0,8(sp) + 5ec: 01010413 addi s0,sp,16 + 5f0: 00002797 auipc a5,0x2 + 5f4: a6878793 addi a5,a5,-1432 # 2058 <global_symbol> + 5f8: 0007b783 ld a5,0(a5) + 5fc: 00f037b3 snez a5,a5 + 600: 0ff7f793 andi a5,a5,255 + 604: 0007879b sext.w a5,a5 + 608: 00078513 mv a0,a5 + 60c: 00813403 ld s0,8(sp) + 610: 01010113 addi sp,sp,16 + 614: 00008067 ret +... +``` + +There you see the relocation was resolved (`0x5f0` and `0x5f4`) by the linker +and the final values have been added. `objdump` is intelligent enough to tell +us where are those instructions pointing (says `2058 <global_symbol>`). Just to +make sure we can search in the symbol table for the `global_symbol`: + +``` asdf +$ riscv64-linux-gnu-objdump -t b.out | grep global_symbol +0000000000002058 g O .bss 0000000000000008 global_symbol +``` + +> NOTE: We could try to calculate the address of the `global_symbol` as the +> linker did, but it's a little bit complicated because we also linked the file +> with the standard library and the startup files, which adds the `crt` files +> on top of the file. It's really that we get more code than what we had in the +> assembly file. If you want to see that, you can see the rest of the output of +> the command, or even try with `--disassemble-all` and calculate the symbol +> address by hand. Good luck. + +#### More sections + +If you want the review some simple things, like a string section, you can use +`readelf` for that. The `-p` flag (equivalent to `--string-dump=`) displays the +contents of the section as strings. You can read the `.comment` section that +way: + +``` asdf +$ riscv64-linux-gnu-readelf -p .comment b.o + +String dump of section '.comment': + [ 1] GCC: (Debian 10.2.1-6) 10.2.1 20210110 +``` + +This is what we had inserted in `.ident` on the assembly file by the compiler. +We have it in the binary too. + +In other distros the output is a little bit different. Look the output we have +in Guix: + +``` asdf +String dump of section '.comment': + [ 1] GCC: (GNU) 11.2.0 +``` + +### Conclusion + +So this whole this just to explain that ELF files are some kind of dual files +that have two different goals at the same time. The executable one is kind of a +picture of the memory state that can be used for loading that state in the +memory, while the linking one just describes how different parts of the +contents relate to each other and has tons of funny tricks to make the files +relocatable, position independent and that kind of things. Cool. + +There are still many fields of ELF we didn't talk about but I consider this +introduction more than enough. Having a simple understanding about how is the +file organized and what kind of information it has is probably enough for the +things we are going to need. + +The proposed example shows that with the knowledge obtained by this short +introduction we can dig a little bit on the files that result from a +compilation and analyze their internals. That's mostly the work I'll need to do +when I start combining compilers in a pipeline of death and destruction. + +If I ever need to dig on something deeper, I'll do. + +Anyway, I'm still unsure if I answered the question we left in the previous +post[^cliff]: + +> Why is learning about ELF interesting if GCC generates assembly? + +Did I? + +[^cliff]: It was a good cliffhanger, though. diff --git a/content/bootstrapGcc/NGIAssure.svg b/content/bootstrapGcc/NGIAssure.svg new file mode 100644 index 0000000..62b7c12 --- /dev/null +++ b/content/bootstrapGcc/NGIAssure.svg @@ -0,0 +1 @@ +<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 657.78 167.13"><defs><style>.cls-1{fill:url(#Sfumatura_senza_nome_277);}.cls-2{fill:#fff;}.cls-3{fill:#5590a1;}</style><linearGradient id="Sfumatura_senza_nome_277" x1="365.94" y1="183.94" x2="132.1" y2="411.34" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#5697ff"/><stop offset="1" stop-color="#6a0041"/></linearGradient></defs><title>Logo-NGIAssure-tag</title><path class="cls-1" d="M425,292.31l-15.21-15.13a12.77,12.77,0,0,1-3.78-9.07v-35.5a18.6,18.6,0,0,0-18.54-18.54H110.59a18.59,18.59,0,0,0-18.53,18.54V362.66a18.59,18.59,0,0,0,18.53,18.54H387.45A18.59,18.59,0,0,0,406,362.66V332a12.81,12.81,0,0,1,3.75-9L425,307.72A10.88,10.88,0,0,0,425,292.31Z" transform="translate(-92.06 -214.07)"/><path class="cls-2" d="M363.52,244.17h0a12.37,12.37,0,0,1,12.38,12.37v82.19a12.38,12.38,0,0,1-12.38,12.38h0a12.37,12.37,0,0,1-12.37-12.38V256.54A12.37,12.37,0,0,1,363.52,244.17Z" transform="translate(-92.06 -214.07)"/><path class="cls-2" d="M323.46,296H309.75A12.66,12.66,0,0,0,297,307.51a12.38,12.38,0,0,0,12.35,13.2h0a1.94,1.94,0,0,1,1.86,2.5,10.9,10.9,0,0,1-7.62,7.27,43.23,43.23,0,0,1-11.08,1.38,36.34,36.34,0,0,1-17.95-4.36,31.28,31.28,0,0,1-12.3-12.14,38,38,0,0,1,0-35.6,30.69,30.69,0,0,1,12.37-12.06,37.78,37.78,0,0,1,18.18-4.28,36.28,36.28,0,0,1,21,6.38,11,11,0,0,0,13-.28,10.86,10.86,0,0,0-.53-17.54,53.58,53.58,0,0,0-9.25-4.91,66.32,66.32,0,0,0-25.51-4.73,63.67,63.67,0,0,0-30.25,7.1,52.6,52.6,0,0,0-21,19.71,57.4,57.4,0,0,0,0,57,52.92,52.92,0,0,0,20.85,19.71,62.57,62.57,0,0,0,29.94,7.1,78.39,78.39,0,0,0,23.07-3.51l.23-.07A28.56,28.56,0,0,0,334.34,322V306.84A10.88,10.88,0,0,0,323.46,296Z" transform="translate(-92.06 -214.07)"/><path class="cls-2" d="M220.23,256.39v82.5A12.22,12.22,0,0,1,208,351.11h-2.32a12.22,12.22,0,0,1-9.45-4.47L155.6,297.15a5.08,5.08,0,0,0-9,3.22v38.52a12.22,12.22,0,0,1-12.22,12.22h0a12.22,12.22,0,0,1-12.22-12.22v-82.5a12.22,12.22,0,0,1,12.22-12.22h2.46a12.2,12.2,0,0,1,9.46,4.48l40.49,49.44a5.07,5.07,0,0,0,9-3.21V256.39A12.23,12.23,0,0,1,208,244.17h0A12.22,12.22,0,0,1,220.23,256.39Z" transform="translate(-92.06 -214.07)"/><path class="cls-3" d="M500.43,308H483l-3.32,8.05h-8.92l16.75-37.58h8.59l16.8,37.58h-9.12Zm-2.74-6.61-6-14.38-6,14.38Z" transform="translate(-92.06 -214.07)"/><path class="cls-3" d="M531.27,315.49a20.07,20.07,0,0,1-6.68-3.14l2.95-6.55a19.88,19.88,0,0,0,5.74,2.85,21.47,21.47,0,0,0,6.66,1.07,10.58,10.58,0,0,0,5.48-1.1,3.32,3.32,0,0,0,1.77-2.92,2.79,2.79,0,0,0-1.05-2.23,7.82,7.82,0,0,0-2.68-1.42c-1.09-.36-2.57-.75-4.43-1.18a60.44,60.44,0,0,1-7-2,11.4,11.4,0,0,1-4.7-3.28,8.82,8.82,0,0,1-2-6,10.46,10.46,0,0,1,1.77-5.93,11.87,11.87,0,0,1,5.34-4.22,22,22,0,0,1,8.73-1.55,29,29,0,0,1,7,.85,21.1,21.1,0,0,1,6,2.47l-2.68,6.61a21,21,0,0,0-10.42-3,9.72,9.72,0,0,0-5.39,1.19,3.58,3.58,0,0,0-1.75,3.11,3,3,0,0,0,2,2.87,30.79,30.79,0,0,0,6.14,1.85,61,61,0,0,1,7,2,11.72,11.72,0,0,1,4.7,3.22,8.64,8.64,0,0,1,2,6,10.25,10.25,0,0,1-1.8,5.88,12.15,12.15,0,0,1-5.39,4.22,22.16,22.16,0,0,1-8.75,1.55A30.59,30.59,0,0,1,531.27,315.49Z" transform="translate(-92.06 -214.07)"/><path class="cls-3" d="M576.26,315.49a20,20,0,0,1-6.69-3.14l3-6.55a19.88,19.88,0,0,0,5.74,2.85,21.47,21.47,0,0,0,6.66,1.07,10.57,10.57,0,0,0,5.47-1.1,3.32,3.32,0,0,0,1.77-2.92,2.81,2.81,0,0,0-1-2.23,7.87,7.87,0,0,0-2.69-1.42c-1.09-.36-2.57-.75-4.43-1.18a61.64,61.64,0,0,1-7-2,11.47,11.47,0,0,1-4.7-3.28,8.87,8.87,0,0,1-2-6,10.4,10.4,0,0,1,1.78-5.93,11.87,11.87,0,0,1,5.34-4.22,21.94,21.94,0,0,1,8.72-1.55,29,29,0,0,1,7,.85,21,21,0,0,1,6,2.47l-2.68,6.61a20.93,20.93,0,0,0-10.41-3,9.73,9.73,0,0,0-5.4,1.19,3.59,3.59,0,0,0-1.74,3.11,3,3,0,0,0,2,2.87,30.71,30.71,0,0,0,6.15,1.85,61.64,61.64,0,0,1,7,2,11.79,11.79,0,0,1,4.7,3.22,8.68,8.68,0,0,1,1.95,6,10.32,10.32,0,0,1-1.79,5.88,12.13,12.13,0,0,1-5.4,4.22,22.13,22.13,0,0,1-8.75,1.55A30.52,30.52,0,0,1,576.26,315.49Z" transform="translate(-92.06 -214.07)"/><path class="cls-3" d="M621.67,312.25q-4.49-4.46-4.48-12.73v-21h8.69V299.2q0,10.1,8.38,10.09a7.82,7.82,0,0,0,6.22-2.44c1.44-1.63,2.15-4.18,2.15-7.65V278.48h8.59v21q0,8.28-4.48,12.73t-12.53,4.45Q626.16,316.7,621.67,312.25Z" transform="translate(-92.06 -214.07)"/><path class="cls-3" d="M694.49,316.06l-7.25-10.47h-8v10.47h-8.69V278.48h16.26a21,21,0,0,1,8.67,1.66,12.42,12.42,0,0,1,7.65,12A12.22,12.22,0,0,1,695.4,304l8.43,12.08Zm-2.2-28.8a9.13,9.13,0,0,0-6-1.69h-7.09v13.09h7.09a9.07,9.07,0,0,0,6-1.71,6,6,0,0,0,2-4.84A5.93,5.93,0,0,0,692.29,287.26Z" transform="translate(-92.06 -214.07)"/><path class="cls-3" d="M749.83,309.08v7H720.74V278.48h28.4v7H729.38v8.16h17.45v6.76H729.38v8.7Z" transform="translate(-92.06 -214.07)"/></svg> diff --git a/content/bootstrapGcc/nlnet.svg b/content/bootstrapGcc/nlnet.svg new file mode 100644 index 0000000..373c8d8 --- /dev/null +++ b/content/bootstrapGcc/nlnet.svg @@ -0,0 +1,34 @@ +<?xml version="1.0" standalone="no"?> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> +<!-- Created using Karbon14, part of koffice: http://www.koffice.org/karbon --> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="449px" height="168px"> + <defs> + </defs> + <g id="Layer"> + </g> + <g id="Layer"> + <path fill="#98bf00" d="M446.602 73.8789L449.102 60.234L436.207 60.234L439.957 40.145L424.512 46.191L422.012 60.234L412.617 60.234L410.117 73.8789L419.363 73.8789L416.215 91.1719C416.066 92.125 415.816 93.5234 415.566 95.3203C415.316 97.1211 415.164 98.7188 415.164 100.07C415.215 106.316 416.715 111.465 419.664 115.516C422.613 119.66 427.41 122.109 434.109 122.859L440.555 109.566C437.105 109.117 434.508 107.766 432.66 105.469C430.809 103.117 429.91 100.168 429.91 96.5703C429.91 95.8711 430.012 94.8711 430.16 93.5234C430.309 92.1719 430.461 91.0742 430.609 90.2227L433.609 73.8789L446.602 73.8789L446.602 73.8789Z" /> + <path fill="#98bf00" d="M310.707 72.332C313.105 71.4805 315.207 71.0312 316.957 71.0312C318.855 71.0312 320.453 71.582 321.754 72.6797C323.004 73.7305 323.602 75.2812 323.602 77.4297C323.602 78.0273 323.504 78.9297 323.301 80.1797C323.102 81.3281 322.953 82.3789 322.805 83.2773L319.203 100.168C318.953 101.469 318.703 102.82 318.453 104.219C318.203 105.668 318.105 106.918 318.105 107.965C318.105 112.016 319.203 115.414 321.453 118.113C323.602 120.812 327.449 122.41 333 122.859L339.348 110.016C337.195 109.668 335.648 108.867 334.699 107.617C333.699 106.418 333.199 104.719 333.199 102.57C333.199 102.07 333.25 101.469 333.348 100.82C333.398 100.168 333.5 99.6211 333.547 99.2188L337.195 82.0273C337.496 80.5781 337.746 79.1289 337.945 77.6797C338.148 76.2812 338.246 74.8789 338.246 73.5312C338.246 68.582 336.797 64.586 333.898 61.637C330.949 58.688 326.852 57.188 321.602 57.188C318.555 57.188 315.656 57.688 312.809 58.688C310.008 59.637 306.609 61.234 302.66 63.586C302.512 62.637 302.16 61.484 301.66 60.188C301.113 58.938 300.512 57.836 299.863 56.836L286.469 62.586C287.617 64.336 288.516 66.184 289.066 68.082C289.566 69.9805 289.816 71.7812 289.816 73.4297C289.816 74.2812 289.766 75.3281 289.617 76.4805C289.516 77.6289 289.367 78.5273 289.215 79.1797L281.27 121.512L295.664 121.512L304.109 75.8281C306.16 74.2812 308.359 73.1289 310.707 72.332L310.707 72.332Z" /> + <path fill="#98bf00" d="M350.742 80.0781C349.191 84.6758 348.441 89.5742 348.441 94.7227C348.441 99.2188 349.043 103.219 350.191 106.719C351.34 110.215 352.992 113.164 355.09 115.516C357.141 117.914 359.688 119.711 362.637 120.961C365.586 122.211 368.883 122.859 372.484 122.859C376.832 122.859 381.129 122.062 385.43 120.461C389.777 118.863 393.574 116.363 396.824 113.016L391.426 100.519C388.926 103.32 386.176 105.418 383.129 106.867C380.078 108.316 377.031 109.016 374.031 109.016C370.535 109.016 367.785 107.918 365.785 105.719C363.836 103.469 362.836 100.668 362.836 97.3711L362.836 96.4219C362.836 96.0234 362.887 95.6211 362.988 95.2227C365.637 94.8711 368.633 94.4219 371.984 93.8242C375.332 93.2227 378.73 92.5234 382.18 91.7227C385.629 90.875 388.977 89.9258 392.273 88.9258C395.523 87.9258 398.422 86.875 400.871 85.8242L400.871 80.0781C400.871 76.5312 400.32 73.332 399.223 70.4805C398.074 67.734 396.574 65.332 394.625 63.285C392.676 61.285 390.324 59.785 387.676 58.785C385.078 57.738 382.23 57.188 379.18 57.188C374.73 57.188 370.582 58.188 366.836 60.137C363.035 62.086 359.789 64.785 357.141 68.2344C354.391 71.6328 352.293 75.5781 350.742 80.0781L350.742 80.0781ZM372.383 69.9805C373.934 69.1328 375.684 68.7344 377.633 68.7344C380.281 68.7344 382.48 69.582 384.227 71.332C385.977 73.0312 386.879 75.5781 386.879 79.0273C385.43 79.4766 383.727 80.0273 381.73 80.5781C379.68 81.0781 377.633 81.5781 375.531 82.0273C373.383 82.4766 371.332 82.9258 369.285 83.3281C367.234 83.6758 365.484 83.9766 363.984 84.2266C364.234 82.1289 364.688 80.1289 365.387 78.2773C366.137 76.4297 367.086 74.7812 368.234 73.3789C369.484 71.9805 370.832 70.832 372.383 69.9805L372.383 69.9805Z" fill-rule="evenodd" /> + <path fill="#000000" d="M404.172 140.453C404.172 139.203 403.969 138.055 403.57 137.055C403.172 136.055 402.621 135.207 401.973 134.457C401.27 133.758 400.473 133.207 399.523 132.856C398.574 132.508 397.523 132.309 396.422 132.309C394.973 132.309 393.625 132.606 392.375 133.156C391.125 133.707 390.027 134.508 389.078 135.504C388.125 136.504 387.379 137.656 386.828 139.004C386.277 140.356 385.977 141.805 385.977 143.402C385.977 144.652 386.176 145.75 386.578 146.801C386.926 147.801 387.477 148.652 388.176 149.352C388.828 150.101 389.676 150.648 390.625 151.051C391.574 151.399 392.625 151.598 393.773 151.598C395.176 151.598 396.523 151.301 397.773 150.75C399.023 150.199 400.121 149.398 401.07 148.402C402.02 147.449 402.77 146.25 403.32 144.902C403.871 143.551 404.172 142.055 404.172 140.453L404.172 140.453ZM390.277 140.402C390.574 139.504 390.977 138.703 391.477 138.004C392.023 137.305 392.676 136.754 393.426 136.305C394.176 135.856 394.973 135.656 395.922 135.656C397.371 135.656 398.422 136.106 399.172 137.004C399.922 137.856 400.32 139.106 400.32 140.652C400.32 141.602 400.172 142.555 399.871 143.504C399.621 144.402 399.223 145.203 398.672 145.902C398.121 146.602 397.473 147.152 396.723 147.601C395.973 148 395.125 148.199 394.223 148.199C392.773 148.199 391.727 147.75 390.977 146.902C390.227 146 389.824 144.801 389.824 143.254C389.824 142.305 389.977 141.352 390.277 140.402L390.277 140.402Z" fill-rule="evenodd" /> + <path fill="#000000" d="M434.559 132.559L431.008 132.559L429.109 143.602C429.059 143.754 429.012 144.004 429.012 144.352C429.012 144.703 429.012 144.953 429.012 145.203L428.859 145.203L422.465 132.559L419.113 132.559L415.766 151.301L419.363 151.301L421.363 140.004C421.414 139.856 421.414 139.606 421.414 139.356C421.414 139.106 421.414 138.805 421.414 138.504L421.563 138.504L428.109 151.449L431.309 151.149L434.559 132.559L434.559 132.559Z" /> + <path fill="#000000" d="M374.383 132.559L370.734 132.559L367.387 151.301L371.082 151.301L374.383 132.559L374.383 132.559Z" /> + <path fill="#000000" d="M328.949 132.559L324.703 132.559C323.902 133.906 323.051 135.457 322.102 137.106C321.152 138.754 320.254 140.453 319.355 142.152C318.453 143.852 317.656 145.5 316.906 147.102C316.156 148.699 315.555 150.101 315.105 151.301L318.953 151.301C319.105 150.949 319.254 150.5 319.453 150.051C319.652 149.602 319.855 149.102 320.105 148.652C320.305 148.199 320.504 147.75 320.703 147.301C320.902 146.852 321.102 146.453 321.254 146.102L327.75 146.102C327.801 146.551 327.801 147 327.852 147.5L328 148.949C328.051 149.398 328.102 149.852 328.152 150.301C328.199 150.75 328.199 151.098 328.199 151.449L331.898 151.149C331.898 150.449 331.848 149.648 331.75 148.699C331.699 147.75 331.551 146.75 331.398 145.703C331.25 144.652 331.098 143.504 330.898 142.351C330.75 141.203 330.551 140.055 330.301 138.906C330.102 137.754 329.898 136.656 329.648 135.555C329.398 134.508 329.199 133.508 328.949 132.559L328.949 132.559ZM326.602 138.106C326.703 138.656 326.801 139.254 326.902 139.902C327 140.504 327.102 141.106 327.152 141.652C327.25 142.203 327.301 142.601 327.352 142.953L322.703 142.953C322.953 142.504 323.203 142.004 323.453 141.453C323.754 140.902 324.051 140.305 324.352 139.703C324.703 139.106 325 138.555 325.301 138.004C325.602 137.453 325.852 136.957 326.102 136.606L326.301 136.606C326.402 137.004 326.5 137.504 326.602 138.106L326.602 138.106Z" fill-rule="evenodd" /> + <path fill="#000000" d="M357.641 135.957L358.188 132.559L345.395 132.559L344.844 135.957L349.391 135.957L346.742 151.301L350.391 151.301L353.09 135.957L357.641 135.957L357.641 135.957Z" /> + <path fill="#000000" d="M297.465 132.309C296.414 132.309 295.363 132.356 294.312 132.457C293.266 132.606 292.266 132.758 291.316 133.008L288.168 150.852C289.117 151.098 290.215 151.25 291.414 151.399C292.566 151.551 293.664 151.598 294.715 151.598C296.262 151.598 297.664 151.348 299.012 150.852C300.363 150.301 301.562 149.602 302.562 148.652C303.559 147.699 304.359 146.551 304.961 145.203C305.508 143.852 305.809 142.305 305.809 140.606C305.809 139.254 305.609 138.106 305.211 137.055C304.762 136.004 304.211 135.156 303.461 134.457C302.711 133.758 301.812 133.207 300.812 132.856C299.762 132.508 298.664 132.309 297.465 132.309L297.465 132.309ZM296.664 135.707C297.414 135.707 298.113 135.805 298.762 135.957C299.414 136.106 299.961 136.406 300.41 136.805C300.91 137.203 301.312 137.703 301.562 138.356C301.812 138.953 301.961 139.703 301.961 140.652C301.961 141.852 301.812 142.902 301.461 143.852C301.16 144.801 300.711 145.602 300.113 146.25C299.512 146.902 298.812 147.352 297.961 147.699C297.113 148.051 296.215 148.199 295.164 148.199C294.715 148.199 294.266 148.199 293.715 148.152C293.164 148.102 292.664 148.051 292.316 148L294.465 135.906C294.766 135.856 295.164 135.805 295.613 135.754C296.062 135.707 296.414 135.707 296.664 135.707L296.664 135.707Z" fill-rule="evenodd" /> + <path fill="#000000" d="M185.809 62.586C186.957 64.336 187.855 66.184 188.406 68.082C188.906 69.9805 189.156 71.7812 189.156 73.4297C189.156 74.2812 189.105 75.3281 188.957 76.4805C188.855 77.6289 188.707 78.5273 188.555 79.1797L180.609 121.512L195.004 121.512L203.449 75.8281C205.5 74.2812 207.699 73.1289 210.047 72.332C212.445 71.4805 214.547 71.0312 216.297 71.0312C218.195 71.0312 219.793 71.582 221.094 72.6797C222.344 73.7305 222.941 75.2812 222.941 77.4297C222.941 78.0273 222.844 78.9297 222.645 80.1797C222.441 81.3281 222.293 82.3789 222.145 83.2773L218.543 100.168C218.293 101.469 218.043 102.82 217.793 104.219C217.547 105.668 217.445 106.918 217.445 107.965C217.445 112.016 218.543 115.414 220.793 118.113C222.941 120.812 226.793 122.41 232.34 122.859L238.688 110.016C236.539 109.668 234.988 108.867 234.039 107.617C233.039 106.418 232.539 104.719 232.539 102.57C232.539 102.07 232.59 101.469 232.688 100.82C232.738 100.168 232.84 99.6211 232.891 99.2188L236.539 82.0273C236.836 80.5781 237.086 79.1289 237.285 77.6797C237.488 76.2812 237.586 74.8789 237.586 73.5312C237.586 68.582 236.137 64.586 233.238 61.637C230.289 58.688 226.191 57.188 220.945 57.188C217.895 57.188 214.996 57.688 212.148 58.688C209.348 59.637 205.949 61.234 202 63.586C201.852 62.637 201.5 61.484 201 60.188C200.453 58.938 199.852 57.836 199.203 56.836L185.809 62.586L185.809 62.586Z" /> + <path fill="#000000" d="M276.82 31.547L262.676 31.547L251.883 90.0234C251.43 91.9727 251.082 94.0234 250.832 96.1719C250.582 98.2695 250.434 100.219 250.434 102.019C250.434 107.816 251.531 112.566 253.781 116.262C256.031 119.961 259.828 122.16 265.176 122.859L271.672 109.566C270.625 109.066 269.723 108.516 268.875 107.918C268.023 107.367 267.324 106.617 266.773 105.769C266.176 104.918 265.727 103.918 265.477 102.719C265.227 101.519 265.074 100.019 265.074 98.2695C265.074 97.4219 265.125 96.4727 265.227 95.4727C265.375 94.4219 265.527 93.3711 265.676 92.2734L276.82 31.547L276.82 31.547Z" /> + <path fill="#000000" d="M246.434 132.559L242.785 132.559L240.387 146.25C239.887 146.801 239.285 147.25 238.535 147.652C237.785 148 236.988 148.199 236.086 148.199C235.188 148.199 234.488 148 233.988 147.601C233.438 147.152 233.188 146.453 233.188 145.402C233.188 145.203 233.238 144.902 233.289 144.504C233.34 144.152 233.34 143.801 233.387 143.504L235.387 132.559L231.688 132.559L229.738 143.453C229.691 143.902 229.641 144.352 229.59 144.801C229.539 145.25 229.539 145.602 229.539 145.953C229.539 146.953 229.691 147.801 229.988 148.551C230.289 149.301 230.691 149.852 231.191 150.301C231.738 150.75 232.34 151.098 232.988 151.301C233.688 151.5 234.387 151.598 235.137 151.598C236.988 151.598 238.637 151.051 240.137 149.898C240.137 150.148 240.137 150.449 240.188 150.75C240.188 151 240.188 151.25 240.234 151.5L243.883 151.25C243.836 151 243.836 150.75 243.836 150.449C243.785 150.199 243.785 149.898 243.785 149.551C243.785 148.949 243.836 148.301 243.883 147.652C243.934 146.953 243.984 146.301 244.133 145.703L246.434 132.559L246.434 132.559Z" /> + <path fill="#000000" d="M276.621 132.559L273.074 132.559L271.172 143.602C271.125 143.754 271.074 144.004 271.074 144.352C271.074 144.703 271.074 144.953 271.074 145.203L270.922 145.203L264.527 132.559L261.176 132.559L257.828 151.301L261.426 151.301L263.426 140.004C263.477 139.856 263.477 139.606 263.477 139.356C263.477 139.106 263.477 138.805 263.477 138.504L263.625 138.504L270.176 151.449L273.371 151.149L276.621 132.559L276.621 132.559Z" /> + <path fill="#000000" d="M214.797 134.457C214.098 133.758 213.297 133.207 212.348 132.856C211.398 132.508 210.348 132.309 209.25 132.309C207.801 132.309 206.449 132.606 205.199 133.156C203.949 133.707 202.852 134.508 201.902 135.504C200.953 136.504 200.203 137.656 199.652 139.004C199.102 140.356 198.801 141.805 198.801 143.402C198.801 144.652 199.004 145.75 199.402 146.801C199.754 147.801 200.301 148.652 201 149.352C201.652 150.101 202.5 150.648 203.449 151.051C204.398 151.399 205.449 151.598 206.598 151.598C208 151.598 209.348 151.301 210.598 150.75C211.848 150.199 212.945 149.398 213.895 148.402C214.848 147.449 215.598 146.25 216.145 144.902C216.695 143.551 216.996 142.055 216.996 140.453C216.996 139.203 216.797 138.055 216.395 137.055C215.996 136.055 215.445 135.207 214.797 134.457L214.797 134.457ZM204.301 138.004C204.852 137.305 205.5 136.754 206.25 136.305C207 135.856 207.801 135.656 208.75 135.656C210.199 135.656 211.246 136.106 211.996 137.004C212.746 137.856 213.148 139.106 213.148 140.652C213.148 141.602 212.996 142.555 212.695 143.504C212.445 144.402 212.047 145.203 211.496 145.902C210.949 146.602 210.297 147.152 209.547 147.601C208.797 148 207.949 148.199 207.051 148.199C205.602 148.199 204.551 147.75 203.801 146.902C203.051 146 202.652 144.801 202.652 143.254C202.652 142.305 202.801 141.352 203.102 140.402C203.402 139.504 203.801 138.703 204.301 138.004L204.301 138.004Z" fill-rule="evenodd" /> + <path fill="#000000" d="M188.258 132.559L177.961 132.559L174.613 151.301L178.312 151.301L179.559 144.152L186.309 144.152L186.906 140.754L180.16 140.754L181.008 135.957L187.656 135.957L188.258 132.559L188.258 132.559Z" /> + <path fill="#98bf00" d="M127.082 44.891C128.43 33.945 125.684 24.102 118.883 15.402C112.086 6.707 103.191 1.66 92.2461 0.309C81.3008 -1.039 71.4531 1.711 62.7578 8.508C54.7109 14.754 49.8125 22.801 48.0625 32.648C47.9141 33.496 47.7617 34.297 47.6641 35.145C47.5625 35.996 47.5117 36.797 47.4648 37.594C47.1133 42.191 47.5625 46.59 48.7617 50.789C50.1133 55.688 52.4609 60.285 55.8594 64.633C59.2578 68.9805 63.1563 72.3828 67.6055 74.9297C71.3516 77.0781 75.5 78.5273 80.0508 79.3281C80.8516 79.4766 81.6484 79.5781 82.5 79.7266C82.9492 79.7773 83.3984 79.8281 83.8477 79.8789C84.9492 75.4297 86.6484 71.2812 88.9961 67.531C87.4453 67.582 85.8477 67.531 84.25 67.383C84.1484 67.332 84.0977 67.332 84.0469 67.332C82.1992 67.082 80.3984 66.734 78.75 66.184C73.6016 64.535 69.2539 61.484 65.707 56.938C62.1562 52.391 60.2578 47.441 59.9062 42.043C59.8086 40.293 59.8594 38.543 60.1094 36.695C60.1094 36.645 60.1094 36.547 60.1094 36.496C61.0586 29.047 64.5078 23 70.4531 18.352C76.4531 13.703 83.1992 11.805 90.7461 12.754C98.293 13.656 104.391 17.102 109.039 23.102C113.688 29.098 115.586 35.844 114.688 43.395C114.438 45.094 114.137 46.691 113.688 48.242C117.887 46.891 122.281 46.191 126.883 46.242C126.93 45.793 127.031 45.344 127.082 44.891L127.082 44.891Z" /> + <path fill="#98bf00" d="M132.328 51.488C131.48 51.391 130.68 51.289 129.828 51.238C125.23 50.941 120.832 51.391 116.637 52.539C111.738 53.887 107.141 56.289 102.789 59.688C98.4414 63.035 95.043 66.934 92.5469 71.3828C90.3945 75.1289 88.9453 79.2773 88.0977 83.8281C92.4453 84.5742 96.4453 85.8242 100.141 87.6758C100.391 85.875 100.742 84.1758 101.242 82.5781C102.891 77.4297 105.941 73.082 110.488 69.5312C115.035 65.984 119.984 64.035 125.434 63.684C127.18 63.586 128.93 63.633 130.781 63.883C130.828 63.883 130.879 63.883 130.93 63.883C138.375 64.836 144.426 68.332 149.074 74.2812C153.77 80.2266 155.668 86.9766 154.719 94.5234C153.77 102.07 150.32 108.168 144.375 112.863C138.426 117.512 131.68 119.363 124.23 118.461C125.082 122.512 125.332 126.758 125.031 131.156C134.977 131.809 143.973 128.957 152.02 122.711C160.719 115.914 165.766 107.016 167.113 96.0703C168.465 85.125 165.715 75.2812 158.918 66.582C152.621 58.535 144.574 53.637 134.777 51.891C133.93 51.738 133.129 51.59 132.328 51.488L132.328 51.488Z" /> + <path fill="#000000" d="M128.93 78.7266C125.48 78.3281 122.434 79.1797 119.684 81.3281C116.934 83.4766 115.387 86.2266 114.984 89.625C114.535 93.0742 115.387 96.1211 117.535 98.8711C119.684 101.621 122.434 103.168 125.883 103.57C129.281 104.019 132.328 103.168 135.078 101.019C137.828 98.8711 139.375 96.1211 139.824 92.6719C140.227 89.2734 139.375 86.2266 137.227 83.4766C135.078 80.7266 132.328 79.1797 128.93 78.7266L128.93 78.7266Z" /> + <path fill="#98bf00" d="M12.8281 73.6289C13.7773 66.082 17.2266 59.938 23.2227 55.289C29.1719 50.641 35.8672 48.742 43.3164 49.691C42.4648 45.641 42.1641 41.395 42.5156 36.996C32.5703 36.344 23.5742 39.145 15.5273 45.441C6.77734 52.238 1.78125 61.137 0.433594 72.082C-0.917969 83.0273 1.78125 92.8242 8.62891 101.57C14.875 109.617 22.9219 114.516 32.7695 116.262C33.5703 116.414 34.3672 116.512 35.2188 116.664C36.0664 116.762 36.8672 116.863 37.7188 116.914C42.3164 117.215 46.7148 116.762 50.9102 115.613C55.7578 114.215 60.4062 111.816 64.7578 108.465C69.0547 105.066 72.4531 101.168 75.0039 96.7695C77.1523 93.0234 78.6016 88.875 79.4492 84.3281C75.1016 83.5781 71.1055 82.2773 67.4062 80.4766C67.1563 82.2266 66.8047 83.9258 66.3047 85.5742C64.6562 90.7227 61.6055 95.0703 57.0586 98.6211C52.5117 102.168 47.5625 104.117 42.1641 104.469C40.4141 104.566 38.6172 104.519 36.7656 104.269C36.7188 104.269 36.668 104.269 36.6172 104.219C29.1719 103.269 23.1211 99.8203 18.4727 93.8711C13.7773 87.875 11.8789 81.1289 12.8281 73.6289L12.8281 73.6289Z" /> + <path fill="#000000" d="M32.4688 67.133C29.7188 69.2305 28.1719 72.0312 27.7227 75.4805C27.3203 78.8281 28.1719 81.8789 30.3203 84.625C32.418 87.375 35.168 88.9727 38.6172 89.4258C42.0664 89.7734 45.1133 88.9258 47.8633 86.8242C50.5625 84.6758 52.1094 81.8789 52.5625 78.5273C53.0117 75.0781 52.1602 71.9805 50.0117 69.2812C47.8633 66.535 45.1133 64.984 41.6641 64.586C38.2148 64.133 35.168 64.984 32.4688 67.133L32.4688 67.133Z" /> + <path fill="#000000" d="M97.293 32.348C95.1445 29.598 92.3438 28.047 88.9453 27.648C85.4961 27.199 82.4492 28.047 79.75 30.199C77 32.297 75.4023 35.098 75.0039 38.543C74.5508 41.941 75.4531 44.992 77.6016 47.742C79.6992 50.441 82.4492 52.039 85.8984 52.488C89.2969 52.84 92.3438 51.988 95.0938 49.891C97.8438 47.742 99.3906 44.941 99.8438 41.594C100.242 38.145 99.3906 35.047 97.293 32.348L97.293 32.348Z" /> + <path fill="#98bf00" d="M85.0469 88.4258C84.5977 88.375 84.1484 88.3242 83.6992 88.2734C82.5977 92.7227 80.8984 96.8711 78.5508 100.621C80.1016 100.519 81.6992 100.57 83.3477 100.769C83.3984 100.769 83.4492 100.769 83.5 100.82C85.3477 101.019 87.0977 101.371 88.7969 101.918C93.9453 103.57 98.293 106.668 101.84 111.215C105.391 115.715 107.289 120.66 107.641 126.109C107.738 127.859 107.688 129.609 107.438 131.457C107.438 131.508 107.438 131.559 107.438 131.656C106.488 139.106 103.039 145.152 97.0938 149.801C91.0938 154.449 84.3477 156.348 76.8008 155.398C69.2539 154.449 63.1563 151 58.5078 145.051C53.8086 139.055 51.9102 132.309 52.8594 124.762C53.0625 123.062 53.4102 121.461 53.9102 119.91C49.6641 121.262 45.2656 121.91 40.6641 121.91C40.6172 122.359 40.5156 122.812 40.4648 123.262C39.1172 134.207 41.8164 144.004 48.6641 152.75C55.4609 161.445 64.3555 166.492 75.3008 167.844C86.2461 169.191 96.043 166.445 104.789 159.645C112.836 153.348 117.734 145.301 119.484 135.457C119.633 134.656 119.734 133.856 119.883 133.008C119.934 132.156 120.035 131.359 120.082 130.559C120.383 125.91 119.934 121.512 118.785 117.363C117.434 112.465 115.035 107.867 111.688 103.519C108.289 99.1719 104.391 95.7227 99.9922 93.2227C96.1953 91.0742 92.0469 89.625 87.4961 88.8242C86.6992 88.6758 85.8984 88.5234 85.0469 88.4258L85.0469 88.4258Z" /> + <path fill="#000000" d="M89.9961 120.41C87.8477 117.664 85.0977 116.113 81.6484 115.664C78.1992 115.266 75.1523 116.113 72.4531 118.262C69.7031 120.41 68.1562 123.16 67.7031 126.559C67.2539 130.008 68.1562 133.059 70.3047 135.805C72.4024 138.555 75.1523 140.106 78.6016 140.504C82.0508 140.953 85.0977 140.106 87.8477 137.953C90.5469 135.805 92.0938 133.059 92.5469 129.609C92.9453 126.211 92.0938 123.16 89.9961 120.41L89.9961 120.41Z" /> + </g> +</svg> |