{"id":18987225,"url":"https://github.com/danbev/learning-llvm","last_synced_at":"2025-04-19T21:23:00.673Z","repository":{"id":45205936,"uuid":"318727575","full_name":"danbev/learning-llvm","owner":"danbev","description":"Project for learning about llvm","archived":false,"fork":false,"pushed_at":"2022-09-13T16:17:29.000Z","size":84,"stargazers_count":14,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-16T21:02:30.179Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danbev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-12-05T07:19:34.000Z","updated_at":"2024-11-23T17:08:19.000Z","dependencies_parsed_at":"2023-01-18T06:15:50.916Z","dependency_job_id":null,"html_url":"https://github.com/danbev/learning-llvm","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danbev%2Flearning-llvm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danbev%2Flearning-llvm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danbev%2Flearning-llvm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danbev%2Flearning-llvm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danbev","download_url":"https://codeload.github.com/danbev/learning-llvm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249808340,"owners_count":21328204,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-08T16:38:41.356Z","updated_at":"2025-04-19T21:23:00.639Z","avatar_url":"https://github.com/danbev.png","language":"C","funding_links":[],"categories":["Starchart"],"sub_categories":[],"readme":"### Learning llvm\nNotes and code samples for learning LLVM.\n\n[Language Reference](https://llvm.org/docs/LangRef.html)\n\n### Intermediate Representation (IR)\nThe contents of the files in this section represent a module in llvm which\nis the top level structure.\n\nLocal values are simliar to registers in assembly language and start with `%`.\n\n#### bitcode\nThe following section will work on an example that looks like this:\n```c\nint something(int nr) {\n  return nr + 2;\n}\n```\n\nTo generate the `bitcode` representation (`bc` extension):\n```console\n$ /usr/bin/clang -emit-llvm -c -o simple.bc simple.c\n```\n\nThe output `simple.bc` can be converted into assembly representation using:\n```console\n$ llvm-dis simple.bc -o simple.ll\n```\nSo lets take a look at the output:\n```text\n; ModuleID = 'simple.c'\nsource_filename = \"simple.c\"\ntarget datalayout = \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\"\ntarget triple = \"x86_64-unknown-linux-gnu\"\n\n; Function Attrs: noinline nounwind optnone uwtable\ndefine dso_local i32 @something(i32) #0 {\n  %2 = alloca i32, align 4\n  store i32 %0, i32* %2, align 4\n  %3 = load i32, i32* %2, align 4\n  %4 = add nsw i32 %3, 2\n  ret i32 %4\n}\n\nattributes #0 = { noinline nounwind optnone uwtable \"correctly-rounded-divide-sqrt-fp-math\"=\"false\" \"disable-tail-calls\"=\"false\" \"less-precise-fpmad\"=\"false\" \"min-legal-vector-width\"=\"0\" \"no-frame-pointer-elim\"=\"true\" \"no-frame-pointer-elim-non-leaf\" \"no-infs-fp-math\"=\"false\" \"no-jump-tables\"=\"false\" \"no-nans-fp-math\"=\"false\" \"no-signed-zeros-fp-math\"=\"false\" \"no-trapping-math\"=\"false\" \"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\" \"target-features\"=\"+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"unsafe-fp-math\"=\"false\" \"use-soft-float\"=\"false\" }\n\n!llvm.module.flags = !{!0}\n!llvm.ident = !{!1}\n\n!0 = !{i32 1, !\"wchar_size\", i32 4}\n!1 = !{!\"clang version 9.0.1 (Fedora 9.0.1-2.fc31)\"}\n```\nThe sections below will go through the above fields.\n\nTo generate the assemble representation:\n```console\n$ /usr/bin/clang -emit-llvm -c -S -o simple.ll simple.c\n```\nThis command will generate a file name `simple.ll`.\n\nAnd a file in assembly representation can be converted into bitcode using:\n```console\n$ llvm-as simple.ll -o simple.bc\n```\n\n### Demangling\nIt can sometimes be difficult to read the IR when the front end uses name\nmangling. This can be demangeled using:\n```console\n$ $ cat main.ll | llvm-cxxfilt\n```\n\n#### target datalayout\nContains information about the endienness and type sizes of the `target triple`\nThis is used for some optimisation that require this information.\n\n```\ntarget datalayout: \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\"\n```\n`e` stands for little endian. If it was big endian it would have been `E`.\nThis is followed by types which have the format:\n```\ntype:\u003csize\u003e:\u003cabi\u003e:\u003cpreferred\u003e\n```\n\n`m:e' stands for name mangling and `e` specified that `ELF` name mangling is\nused.\n\n`i64:64` means that 64 bit integer is 64 bits.\n\n### functions declarations\nAre similar to c fuctions syntax:\n```\ndefine dso_local i32 @main(i32 %0, i8** %1) #0 {\n\n}\n```\n`dso_local` means the compiler may assume that a function or variable marked as\n`dso_local` will resolve to a symbol within the same linkage unit. `dso` stands\nfor `dynamic shared object`.\n\nThe following `i32` is the return value, followed by the name of the function.\nNotice the `@main` specifies this as a global.\n\nAnd main takes one `i32` which will be stored in `%0`, and a pointer-to-pointer\nof `i8` in `%1`.\n\nThen we have the following in the body of the function:\n```\n; Function Attrs: noinline nounwind optnone uwtable                             \ndefine dso_local i32 @something(i32) #0 {                                       \n  %2 = alloca i32, align 4                                                      \n  store i32 %0, i32* %2, align 4                                                \n  %3 = load i32, i32* %2, align 4                                               \n  %4 = add nsw i32 %3, 2                                                        \n  ret i32 %4                                                                    \n}\n```\nNotice `#0` which specifies function attributes (listed further down in the\nfile):\n```\nattributes #0 = { noinline nounwind optnone uwtable\n\"correctly-rounded-divide-sqrt-fp-math\"=\"false\" \"disable-tail-calls\"=\"false\"\n\"less-precise-fpmad\"=\"false\" \"min-legal-vector-width\"=\"0\"\n\"no-frame-pointer-elim\"=\"true\" \"no-frame-pointer-elim-non-leaf\"\n\"no-infs-fp-math\"=\"false\" \"no-jump-tables\"=\"false\" \"no-nans-fp-math\"=\"false\"\n\"no-signed-zeros-fp-math\"=\"false\" \"no-trapping-math\"=\"false\"\n\"stack-protector-buffer-size\"=\"8\" \"target-cpu\"=\"x86-64\"\n\"target-features\"=\"+cx8,+fxsr,+mmx,+sse,+sse2,+x87\" \"unsafe-fp-math\"=\"false\"\n\"use-soft-float\"=\"false\"\n}\n```\n`alloca` will allocate (similar to man alloca?) on the stack. The type will \ndetermine the size of the allocation (sizeof(type)).\n\n```c\nint something(int nr) {\n  return nr + 2;\n}\n```\nWill generate the following llvm IR:\n```\n; Function Attrs: noinline nounwind optnone uwtable                             \ndefine dso_local i32 @something(i32) #0 {                                       \n  %2 = alloca i32, align 4                                                      \n  store i32 %0, i32* %2, align 4                                                \n  %3 = load i32, i32* %2, align 4                                               \n  %4 = add nsw i32 %3, 2                                                        \n  ret i32 %4                                                                    \n}\n```\nFirst space on the stack will be allocated (alloca) that can hold an `i32`.\nNext, we store the value in `%0` which is the passed in `nr`, which is stored\nin the stack (allocated in the previous instruction) `%2`.\n\nNext, the value stored in `%2` will be loaded into `%3`, followed by calling\n`add` with produces a type of `i32` and stores the result in `%4`.\n`nsw` stands for `No Signed Wrap` which means that if there signed overflow the\nresult of this operation will be a poison value.\n\n\n#### store instruction\nStore takes two arguments, a value to store and an address where the value\nshould be saved.\n```\n  store \u003ctype\u003e \u003cvalue\u003e, \u003ctype\u003e* \u003cpointer\u003e\n```\nFor example:\n```\n  store i32 %0, i32* %2, align 4                                                \n```\nSo this is saying store the value that exists in register/local `%0` which is of\ntype `i32` into `%2` as a pointer to `i32`.\n\n#### load instruction\n\n```\n  %3 = load i32, i32* %2, align 4                                               \n```\nLoad a `i32` from `%2` (which is a pointer) which I'm guessing is dereferenced?\n\n\n#### arrays\nAre declared like this:\n```\n%something = type [size/len x type]\n```\nFor example:\n```\n%something = type [15 x i8]\n```\n\n### types/object\nIs used to represent a collection of data members in memory. Like a class or\na struct in some programming languages.\n\nFor example, a type with two i32 values:\n```\n%something = type {i32, i32}\n```\n\nAnother example with a field and a function pointer:\n```\n%\"something_underscore\" = type {i32, void (i32)* }\n```\n\nTaking a look at a more complicated example:\n```\n%\"unwind::libunwind::_Unwind_Exception\" = type { i64, void (i32, %\"unwind::libunwind::_Unwind_Exception\"*)*, [6 x i64] }\n```\nSo the first part is just the name of the variable which needs quotes because of\nthe characters used like `::`, and we can see that this is a struct where the\nfirst member is a i64 value, the second is a function pointer which takes a\n`i32`, and then a pointer to a struct of this same time. The third argument\nis an array of size/len 6 and the types of the entries are `i64`.\n\nNow, if we take a look in the rust source code we can find\n`library/unwind/src/libunwind.rs`:\n```rust\n#[repr(C)]\npub struct _Unwind_Exception {\n    pub exception_class: _Unwind_Exception_Class,\n    pub exception_cleanup: _Unwind_Exception_Cleanup_Fn,\n    pub private: [_Unwind_Word; unwinder_private_data_size],\n}\n\npub type _Unwind_Exception_Cleanup_Fn =\n    extern \"C\" fn(unwind_code: _Unwind_Reason_Code, exception: *mut _Unwind_Exception);\n```\nSo we can see that the `_Unwind_Exception_Cleanup_Fn` is the second parameter\nto the function pointer (second member of the struct). So that is only declaring\nthe a type. And following that we have:\n```llvm\n %\"unwind::libunwind::_Unwind_Context\" = type { [0 x i8] }\n```\nNow, this is also a variable that is declared and the type is an array of size\n0 and of type i8 (1 byte). I think this matched the definition of this enum\nfound in `library/unwind/src/libunwind.rs`:\n```rust\npub enum _Unwind_Context {}\n```\nAnd notice that this is an empty enum, so it does not have any values but it\ncan have associated functions.\n\n```\n@vtable.0 = private unnamed_addr constant\n     \u003c{ i8*, [16 x i8], i8*, i8*, i8* }\u003e\n     \u003c{ i8* bitcast (void (i64**)* @\"core::ptr::drop_in_place$LT$std..rt..lang_start$LT$$LP$$RP$$GT$..$u7b$$u7b$closure$u7d$$u7d$$GT$::hfd0e41c7184d2d5c\" to i8*), [16 x i8] c\"\\08\\00\\00\\00\\00\\00\\00\\00\\08\\00\\00\\00\\00\\00\\00\\00\", i8* bitcast (i32 (i64**)* @\"core::ops::function::FnOnce::call_once$u7b$$u7b$vtable.shim$u7d$$u7d$::h6376c1087f8195c9\" to i8*), i8* bitcast (i32 (i64**)* @\"std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h4a18ec8e9cd2a4c5\" to i8*), i8* bitcast (i32 (i64**)* @\"std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h4a18ec8e9cd2a4c5\" to i8*) }\u003e, align 8\n\n; Function Attrs: nonlazybind uwtable                                           \ndeclare i32 @rust_eh_personality(i32,\n    i32,\n    i64,\n    %\"unwind::libunwind::_Unwind_Exception\"*,\n    %\"unwind::libunwind::_Unwind_Context\"*) unnamed_addr #1\n```\nRecall that a `@` sign means that this is a global identifier and it is external\n`unnamed_addr` means that the address is not significant.\n\n```\ndefine internal void @std::sys_common::backtrace::__rust_begin_short_backtrace::hfb9be5a6e963bdda(void ()* %f)\n   unnamed_addr #0 personality \n   i32 (i32, i32, i64, %\"unwind::libunwind::_Unwind_Exception\"*, %\"unwind::libunwind::_Unwind_Context\"*)* @rust_eh_personality {\n```\n`#0` is the attribute index.\n`personality constant` allows a function to specify what function to use for\nexception handling.\n\n\n### Structures\nNormal (non-packed/not padded)) struct:\n```\n%Foo = type {\n  i32,           // no member name, uses index 0\n  double }       // no member name, uses index 1\n```\nSo notice that we use indexes instead of named members. But we don't use the\nindexes directly as in %someFoo.0, but instead we use `getelementptr` (GEP)\n(more on this instruction later).\n\nPacked structs (padded):\n```\n%Foo = type \u003c{\n  i32,           // no member name, uses index 0\n  double }\u003e      // no member name, uses index 1\n```\n\n\n### Casts\nThere are 9 different types of casts in llvm, Bitwise casts which are type\ncasts, zero-extending casts, sign-extending casts, truncation-casts,\nfloating-point extending casts, address-space casts (pointer casts), Pointer-to-\ninteger casts, etc.\n\n#### Bitwise casts (bitcast)\n```c\n  Foo *foo = (Foo *) malloc(sizeof(Foo));\n```\nWould turn into the following LLVM IR:\n```llvm\n  %1 = call i8* @malloc(i32 4)\n  %foo = bitcast i8* %1 to %Foo*\n```\nNotice that we first have the call to `@malloc` and then the second instruction\ndoes the cast.\n\n### Types\n* `i1` is a one-bit integer (which is used for booleans for example)\n* `i32` is a 32-bit integer\n* `iN` is a N-bit integer\n\nPointer types:\n* [4 x i32]* A pointer to array of four `i32` values\n* i32 addrspace(5)* A pointer to an `i32` value that resides in address space 5.\n* i32 (i32*) * A pointer to a function that takes an `i32*`, returning an `i32`.\n* i8* can be used as pointer to void.\n\n### Metadata\nOne of the main motivations for adding metadata was for debugging information.\nRecall that ELF is the Excecutable and Linkable Format, and it contains all the\ninfo required to load an object file (very simplified but I've written about\nELF before). It also contains debug information and the format most commonly\nused in ELF is DWARF (see the connection of names; elves and dwarfes).\n\nIn llvm IR you might find the following `!3`:\n```llmv\n%_4 = load void ()*, void ()** %0, align 8, !nonnull !3, !noundef !3\n```\nThe `!3` refers to an index into the metadata section later inte file:\n```\n!0 = !{i32 7, !\"PIC Level\", i32 2}                                              \n!1 = !{i32 7, !\"PIE Level\", i32 2}                                              \n!2 = !{i32 2, !\"RtLibUseGOT\", i32 1}                                            \n!3 = !{}                                                                        \n!4 = !{i32 3310276}\n```\n\n### Attributes\nAre markers that define properties on functions, parameters and return values.\n\n#### noalias\nMeans that memory access through a pointer is exclusive, so there are no other\npointers to what this pointer points to.\n\n#### nocapture\nThe pointer is not stored in a global or other memory location that outlives\nthe function.\n\n### landingpad\nThis is an llvm instruction which specifies this basic block as a landingpad\nfor exceptions. This corresponds to the code of catch region of a try-catch\nblock. For example:\n```llvm\ncleanup:                                          ; preds = %bb1\n  %1 = landingpad { i8*, i32 }\n          cleanup\n  %2 = extractvalue { i8*, i32 } %1, 0\n  %3 = extractvalue { i8*, i32 } %1, 1\n  %4 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %0, i32 0, i32 0\n  store i8* %2, i8** %4, align 8\n  %5 = getelementptr inbounds { i8*, i32 }, { i8*, i32 }* %0, i32 0, i32 1\n  store i32 %3, i32* %5, align 8\n  br label %bb3\n```\nIn this case the optional `cleanup` flags indicates that this is a landing pad\nfor a cleanup, which means that this landingpad should always be entered, whic\nI think can be used for running destructors/drop functions.\nIn this case this landing pad can catch a struct with a i8* member and a 32\nmember.\n\nOther possibilities for clauses, apart from `cleanup` are `catch`, and `filter`. \n\n### Invoke instruction\nLets take the following example of an `invoke` instruction and try to understand\nit;\n```llvm\n%2 = invoke i32 @\"std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h4a18ec8e9cd2a4c5\"(i64** align 8 %_1)\n          to label %bb1 unwind label %cleanup\n```\n\n* `i32` is the return type of the function being called.\n*  `@\"std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::h4a18ec8e9cd2a4c5\"`\nis the function pointer.\n*  `i64** align 8 %_1` are the arguments passed to the function.\n*  `to label %bb1` is the basic block to which control will be passed if the\ncalled function returns using `ret`.\n* unwind is a mandatory (non-optional) part of the invoke instruction\n* `label %cleanup` is the basic block to which control will be passed if the\ncalled functions returns using `resume`.\n\n\n### Resume instruction\nTODO:\n\n#### Basic blocks\nThese begin with an optional label, and end with a termination instruction like\nbranch (br) or return (ret).\n\n#### Branch (br)\nThe `br` instruction has two forms, one where there is a condition and one that\nis an unconditional branch.\n```\nbr i1, label_if_true, label_if_false\n\nbr label_destination\n```\n`i1` is a single bit integer and `i32` would be an 32-bit integer.\n\nFor example using [branch.c](./branch.c) we have the following branch in main:\n```llvm\nstore i32 2, i32* %6, align 4\n%8 = load i32, i32* %6, align 4\n%9 = icmp eq i32 %8, 2\nbr i1 %9, label %10, label %11\n\n10:                                               ; preds = %2\n  call void @two()\n  br label %12\n\n11:                                               ; preds = %2\n  call void @one()\n  br label %12\n\n12:\n  ret i32 0\n}\n```\nNote that the comment `; preds = %2` is saying that %2 is the predecessor for\nthis basic block.\n\n#### call\n```\n%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i64 0, i64 0)) \n```\nThe first argument is `i32` which is the return value of printf.\nAfter that we have the signature of printf which is `(i8*, ...)` \n@prinf is pointer to the function which is followed by the arguments. Now, in\nthis case the arguments are retrieved using `getelementptr`\n\n```c\nint printf(const char *format, ...);\n```\n\n#### getelementptr\nIs used to perform address calculations. It takes a a base type that it is\ngoing to operatate on. The second operand is the base pointer itself.\n\n```\n@.str.2 = private unnamed_addr constant [10 x i8] c\"Bajja...\\0A\\00\", align 1\n...\n\ngetelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i64 0, i64 0)) \n\nbase type: [10 x i8]\nbase ptr:  [10 x i8]* @.str.2\ni64 0: base ptr offset, which is a pointer to [10 x i8]\ni64 0: offset into above array  \n```\nThese last two indices are somewhat confusing. The first is an offset of the\nbase type, and the second is a index into that type.\n```\n@.str.2 = private unnamed_addr constant [3 x i8] c\"Ba\\0A\\00\", align 1\n\ngetelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 0)) \n                                          |            |     |\n                       +------------------+            |     |\n                       |-------------------------------|-----+\n                       ↓                               |\n                       +-+-+--+-+-+-+-+-+-+            |\n                       |B|a|\\n|x|x|x|y|y|y|            |\n                       +-+-+--+-+-+-+-+-+-+            |\n                       [  0  ][ 1  ][  2  ]            |\n                          ^                            |\n                          +----------------------------+\n\n#.str.2 will be equal to 'B'\n```\nNotice that the type pointed to by the first offset is an array, in this case\nit is pointing to the same place as the base pointer. If we want to get a\npointer to an element in this array we use the second index:\n```\ngetelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 0, i64 1)) \n                                          |            |     |\n                       +------------------+            |     |\n                       | +-----------------------------|-----+\n                       ↓ ↓                             |\n                       +-+-+--+-+-+-+-+-+-+            |\n                       |B|a|\\n|x|x|x|y|y|y|            |\n                       +-+-+--+-+-+-+-+-+-+            |\n                       [  0  ][ 1  ][  2  ]            |\n                          ^                            |\n                          +----------------------------+\n#.str.2 will be equal to 'a'\n```\nNotice what happens if we use a larger offset for the first index, this is\nlike incrementing a pointer\n```\n\ngetelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i64 1, i64 0)) \n                                          |            |     |\n                       +------------------+            |     |\n                       |      +------------------------|-----+\n                       ↓      ↓                        |\n                       +-+-+--+-+-+-+-+-+-+            |\n                       |B|a|\\n|x|x|x|y|y|y|            |\n                       +-+-+--+-+-+-+-+-+-+            |\n                       [  0  ][ 1  ][  2  ]            |\n                                ^                      |\n                                +----------------------+\n```\nThe result is the address of the indexed element.\n\n#### struct\n```\n%name = type {i8, [3 x i8], i32}\n```\n\n### llc\nI LLVM's static compiler which can take a llvm source, for example a `.ll` file\nand outputs assembly source for the target platform.\n\nFor example, lets take a simple c program and emit the llvm assembly for it:\n```console\n$ /usr/bin/clang -emit-llvm -S -o print.ll print.c\n```\nThis will generate a file name `print.ll` which can then be passed to `llc`:\n```console\n$ /usr/bin/llc print.ll\n```\nWhich will generate a `print.s` file which we can pass to an assembler:\n```console\n$ /usr/bin/as print.s -o print.o\n```\nWhich will generate an object file named `print.o` which then needs to be\nlinked. Now, since [print.c](./print.c) used the c library we need to make sure\nwe link in the correct librarys which would normally be handled by the compiler\ntool chain, like clang or gcc:\n```console\n$ /usr/bin/ld -e main -dynamic-linker /lib64/ld-linux-x86-64.so.2 \\\n       /lib64/crt1.o /lib64/crti.o -lc -arch x86_64 print.o  \\\n       /lib64/crtn.o -o print\n```\nFor some background about the libraries specifed here please see\n[learning-linux-kernel](https://github.com/danbev/learning-linux-kernel#networking).\nIf you want to see what gcc would use to link one can use the following command\nto have gcc show the link command options:\n```console\n$ gcc -### -o print_out print.c\n```\n\nNow we can run our executable:\n```console\n$ ./print\nsomething....\n```\n\nOne can use the `opt` command to generate some useful information in the\nassembly format, like named arguments and labels:\n```console\n$ /usr/bin/opt -S -mem2reg -instnamer print.ll -o print_before_opt.ll\n```\n\n### Link Time Optimizations (LTO)\nAs then name suggests these are optimizations that the linker can perform on\nall the object files that it is linking, so the linker puts all the objects\nfiles together and combines them into a single program.\n\nSo the linker would merge all the object files (which I think can also be\nllvm bit code files but not sure yet) into one big one and then do optimizations\nthe one big merged file. This can allow for optimizations that where not\ndiscovered/possible in earlier stages but can also introduce scalablitlity\nor memory issues while linking.\n\nSo with LTO enabled, by using `-flto\n```console\n$ make lto_a.o\n/usr/bin/clang -flto -c -o lto_a.o lto_a.c\n\n$ file lto_a.o\nlto_a.o: LLVM IR bitcode\n```\nSo we can indeed see that this is a LLVM IR bitcode file and we can inspect it\nusing:\n```console\n$ llvm-dis lto_a.o -o lto_a.ll\n```\nAnd we compile lto_main as a normal object file:\n```console\n$ make lto_main.o \n/usr/bin/clang -c -o lto_main.o lto_main.c \n```\nAnd finally we compile the executable passing in the LLVM IR bitcode and the\nobject code:\n```console\n$ make lto_main\n/usr/bin/clang -flto lto_a.o lto_main.o -o main\n```\n\n### lld (LLVM portable)\nlld is LLVM's linker and supports ELF, COFF, and Mach-O.\nCan be enabled by passing `-fuse-ld=lld` to clang/gcc:\n```\n-fuse-ld=lld\n```\n\n### bfd linker (GNU)\nIs written on top of the [BFD library](https://en.wikipedia.org/wiki/Binary_File_Descriptor_library)\nThis is the traditional GNU binutils linker named `ld`.\n```\n-fuse-ld=bfd\n```\n\n### gold linker (GNU)\nWas written to remove the BFD library abstraction layer.\nThis is the next/news GNU binutils linker named `gold`:\n```\n-fuse-ld=gold\n```\n\n### LLVM Exception Handling (eh)\n\n### invoke\nA call inside a try scope will will be replaces by the LLVM frontend with an\ninvoke instruction. This instruction has two points of continuation, one for\na normal successful call, and one if the call raises an exception.\nIn the case of an exception the place where the code continues execution is\ncalled the `landing pad`.\nThese are alternative function entry points where an exception structure ref\nand a type info index is passed as arguments.\n\n```\ninvoke void @_Z9somethingi(i32 1)                                             \n          to label %9 unwind label %10\n      (if successful) (if throws)\n\n(if successful)\n9:                                                ; preds = %2                  \n  br label %24                                                                  \n                                                                                \n(if throws)\n10:                                               ; preds = %2                  \n  %11 = landingpad { i8*, i32 }   // i8* = exception pointer part, i32=selector value part                                                \n          catch i8* bitcast (i8** @_ZTIi to i8*)                                \n  %12 = extractvalue { i8*, i32 } %11, 0                                        \n  store i8* %12, i8** %6, align 8                                               \n  %13 = extractvalue { i8*, i32 } %11, 1                                        \n  store i32 %13, i32* %7, align 4                                               \n  br label %14        \n```\n\n\n### LLVM tutorial example\nThis section follows the [tutorial](https://llvm.org/docs/tutorial/MyFirstLanguageFrontend/LangImpl01.html)\nand contains notes around it.\n\nBuilding:\n```console\n$ make main\n\"clang++\" \"-g\" -o main lang.o main.cc\n```\nRunning the example:\n```console\n$ ./main lang.example\n```\n\n### libunwind\n```console\n$ sudo yum install libunwind-devel\n```\n\n```\n$ readelf --debug-dump=frames libunwind\n```\n\n### poison value\nTODO:\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanbev%2Flearning-llvm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanbev%2Flearning-llvm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanbev%2Flearning-llvm/lists"}