diff options
Diffstat (limited to 'development')
-rw-r--r-- | development/c++.html | 106 | ||||
-rw-r--r-- | development/c++/Makefile | 5 | ||||
-rw-r--r-- | development/c++/concepts-20.cc | 105 | ||||
-rw-r--r-- | development/ld.so.html | 3 | ||||
-rw-r--r-- | development/ldso/samename/Makefile | 13 | ||||
-rw-r--r-- | development/ldso/samename/lib.c | 9 | ||||
-rw-r--r-- | development/ldso/samename/main.c | 36 |
7 files changed, 275 insertions, 2 deletions
diff --git a/development/c++.html b/development/c++.html index 0d95860..a868300 100644 --- a/development/c++.html +++ b/development/c++.html @@ -813,6 +813,110 @@ static_assert(!is_valid<B>::value, "is false"); </blockquote> <p>A more detailed description is available in the SO discussion <a href="https://stackoverflow.com/a/27688405">How does <code>void_t</code> work</a>.</p> +<h2 id="example-concepts-since-c20"><a class="header" href="#example-concepts-since-c20">Example: Concepts since c++20</a></h2> +<pre><code class="language-cpp">// REQUIRES EXPRESSION +// requires { requirement-seq } +// requires ( parameter-list ) { requirement-seq } +// +// [1] https://en.cppreference.com/w/cpp/language/requires +// [2] https://en.cppreference.com/w/cpp/language/constraints#Constraints +// +// REQUIREMENT CLAUSE +// Not the same as a REQUIREMENT EXPRESSIONS, and is used to require +// constraints (express concept bounds). +// +// [1] https://en.cppreference.com/w/cpp/language/constraints#Requires_clauses + +// -- HELPER ------------------------------------------------------------------- + +template<typename T> +using Alias = T; + +void print(int); + +// -- CONCEPTS & REQUIRE EXPRESSIONS ------------------------------------------- + +// Simple concept from a type trait. +template<typename T, typename U> +concept Same = std::is_same<T, U>::value; + +// Simple requirement concepts. +template<typename T> +concept TraitAddAndPrint = requires(T t, int i) { + // Adding T + int must be supported. + t + i; + // Calling print(T) must be available. + print(t); +}; + +// Type requirement concepts. +template<typename T> +concept TraitTypes = requires(T t) { + // T must have a type definition inner. + typename T::inner; + // Type alias must exist. + typename Alias<T>; +}; + +// Compound requirement concepts. +template<typename T> +concept TraitFns = requires(T t, const T c) { + // void T::foo() must exist. + { t.foo() }; + // bool T::bar() const; must exist. + { c.bar() } -> Same<bool>; + // static void T::stat(); must exist. + { T::stat() } -> Same<int>; +}; + +// Nested requirement concepts. +template<typename T> +concept TraitNested = requires(T t) { + // Must satisfy other concepts. + requires TraitTypes<T>; + requires TraitFns<T>; +}; + +// -- REQUIRE EXPRESSIONS ------------------------------------------------------ + +// Require expressions can be evaluated to booleans. +template<typename T> +static constexpr bool IsTraitFns = requires { requires TraitFns<T>; }; + +// Require expressions can also be used in static assertions. +static_assert(requires { requires Same<int, int>; }); +static_assert(!requires { + typename Alias<int>; + requires Same<int, void>; +}); + +// -- TESTS -------------------------------------------------------------------- + +static_assert(requires { requires TraitAddAndPrint<int>; }); + +struct FnTypeGood { + using inner = int; +}; +struct FnTypeBad {}; +static_assert(requires { requires TraitTypes<FnTypeGood>; }); +static_assert(!requires { requires TraitTypes<FnTypeBad>; }); + +struct FnGood { + void foo(); + bool bar() const; + static int stat(); +}; +struct FnBad {}; +static_assert(requires { requires TraitFns<FnGood>; }); +static_assert(!requires { requires TraitFns<FnBad>; }); + +struct NestedGood : FnTypeGood, FnGood {}; +struct NestedBad1 : FnGood {}; +struct NestedBad2 : FnTypeGood {}; +static_assert(requires { requires TraitNested<NestedGood>; }); +static_assert(!requires { requires TraitNested<NestedBad1>; }); +static_assert(!requires { requires TraitNested<NestedBad2>; }); +</code></pre> <h2 id="template-selection-with-partially--fully-specializations"><a class="header" href="#template-selection-with-partially--fully-specializations">Template selection with partially / fully specializations.</a></h2> <pre><code class="language-cpp">enum Kind { kPrimary, @@ -886,7 +990,7 @@ int main() { // * No specialization matches, take the primary template. } </code></pre> -<h1 id="example-perfect-forwarding"><a class="header" href="#example-perfect-forwarding">Example: Perfect forwarding</a></h1> +<h2 id="example-perfect-forwarding"><a class="header" href="#example-perfect-forwarding">Example: Perfect forwarding</a></h2> <pre><code class="language-cpp">#include <cassert> #include <cstdio> #include <new> diff --git a/development/c++/Makefile b/development/c++/Makefile index 622bfd3..2c53e47 100644 --- a/development/c++/Makefile +++ b/development/c++/Makefile @@ -1,4 +1,4 @@ -SRC = concepts-11.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc fwd.cc fwd-perfect.cc +SRC = concepts-11.cc concepts-20.cc meta.cc meta2.cc meta4.cc tmpl-pair.cc tmpl-void_t.cc fwd.cc fwd-perfect.cc BIN = $(SRC:.cc=) all: $(BIN) @@ -6,6 +6,9 @@ all: $(BIN) %: %.cc $(CXX) -o $* $^ -std=c++17 -g -fsanitize=address -fsanitize=undefined -fsanitize=leak +concepts-20: concepts-20.cc + $(CXX) -fsyntax-only $^ -std=c++20 + fmt: clang-format -i $(SRC) diff --git a/development/c++/concepts-20.cc b/development/c++/concepts-20.cc new file mode 100644 index 0000000..018b30b --- /dev/null +++ b/development/c++/concepts-20.cc @@ -0,0 +1,105 @@ +#include <concepts> +#include <type_traits> + +// REQUIRES EXPRESSION +// requires { requirement-seq } +// requires ( parameter-list ) { requirement-seq } +// +// [1] https://en.cppreference.com/w/cpp/language/requires +// [2] https://en.cppreference.com/w/cpp/language/constraints#Constraints +// +// REQUIREMENT CLAUSE +// Not the same as a REQUIREMENT EXPRESSIONS, and is used to require +// constraints (express concept bounds). +// +// [1] https://en.cppreference.com/w/cpp/language/constraints#Requires_clauses + +// -- HELPER ------------------------------------------------------------------- + +template<typename T> +using Alias = T; + +void print(int); + +// -- CONCEPTS & REQUIRE EXPRESSIONS ------------------------------------------- + +// Simple concept from a type trait. +template<typename T, typename U> +concept Same = std::is_same<T, U>::value; + +// Simple requirement concepts. +template<typename T> +concept TraitAddAndPrint = requires(T t, int i) { + // Adding T + int must be supported. + t + i; + // Calling print(T) must be available. + print(t); +}; + +// Type requirement concepts. +template<typename T> +concept TraitTypes = requires(T t) { + // T must have a type definition inner. + typename T::inner; + // Type alias must exist. + typename Alias<T>; +}; + +// Compound requirement concepts. +template<typename T> +concept TraitFns = requires(T t, const T c) { + // void T::foo() must exist. + { t.foo() }; + // bool T::bar() const; must exist. + { c.bar() } -> Same<bool>; + // static void T::stat(); must exist. + { T::stat() } -> Same<int>; +}; + +// Nested requirement concepts. +template<typename T> +concept TraitNested = requires(T t) { + // Must satisfy other concepts. + requires TraitTypes<T>; + requires TraitFns<T>; +}; + +// -- REQUIRE EXPRESSIONS ------------------------------------------------------ + +// Require expressions can be evaluated to booleans. +template<typename T> +static constexpr bool IsTraitFns = requires { requires TraitFns<T>; }; + +// Require expressions can also be used in static assertions. +static_assert(requires { requires Same<int, int>; }); +static_assert(!requires { + typename Alias<int>; + requires Same<int, void>; +}); + +// -- TESTS -------------------------------------------------------------------- + +static_assert(requires { requires TraitAddAndPrint<int>; }); + +struct FnTypeGood { + using inner = int; +}; +struct FnTypeBad {}; +static_assert(requires { requires TraitTypes<FnTypeGood>; }); +static_assert(!requires { requires TraitTypes<FnTypeBad>; }); + +struct FnGood { + void foo(); + bool bar() const; + static int stat(); +}; +struct FnBad {}; +static_assert(requires { requires TraitFns<FnGood>; }); +static_assert(!requires { requires TraitFns<FnBad>; }); + +struct NestedGood : FnTypeGood, FnGood {}; +struct NestedBad1 : FnGood {}; +struct NestedBad2 : FnTypeGood {}; +static_assert(requires { requires TraitNested<NestedGood>; }); +static_assert(!requires { requires TraitNested<NestedBad1>; }); +static_assert(!requires { requires TraitNested<NestedBad2>; }); diff --git a/development/ld.so.html b/development/ld.so.html index c0d088b..6c0e2f0 100644 --- a/development/ld.so.html +++ b/development/ld.so.html @@ -352,6 +352,9 @@ symbol=default_main; lookup in file=/usr/lib/libc.so.6 [0] symbol=default_main; lookup in file=/lib64/ld-linux-x86-64.so.2 [0] ./main: error: symbol lookup error: undefined symbol: default_main (fatal) </code></pre> +<h2 id="load-lib-with-same-name-from-different-locations"><a class="header" href="#load-lib-with-same-name-from-different-locations">Load lib with same name from different locations</a></h2> +<p>The sources in <a href="https://github.com/johannst/notes/tree/master/src/development/ldso/samename">ldso/samename</a> show some experiments, loading the +libs with the same name but potentially from different locations (paths).</p> <h2 id="dynamic-linking-x86_64"><a class="header" href="#dynamic-linking-x86_64">Dynamic Linking (x86_64)</a></h2> <p>Dynamic linking basically works via one indirect jump. It uses a combination of function trampolines (<code>.plt</code> section) and a function pointer table (<code>.got.plt</code> diff --git a/development/ldso/samename/Makefile b/development/ldso/samename/Makefile new file mode 100644 index 0000000..f35a1e3 --- /dev/null +++ b/development/ldso/samename/Makefile @@ -0,0 +1,13 @@ +all: + mkdir -p foo bar + gcc -g -o foo/lib.so lib.c -shared -fPIC -DNAME=\"foo\" + gcc -g -o bar/lib.so lib.c -shared -fPIC -DNAME=\"bar\" + gcc -g -o main main.c -ldl + ./main foo/lib.so bar/lib.so + LD_LIBRARY_PATH=foo:bar ./main lib.so lib.so + LD_LIBRARY_PATH=bar:foo ./main lib.so lib.so + LD_LIBRARY_PATH=foo ./main lib.so foo/lib.so + LD_LIBRARY_PATH=foo ./main lib.so bar/lib.so + +clean: + $(RM) -r foo bar main diff --git a/development/ldso/samename/lib.c b/development/ldso/samename/lib.c new file mode 100644 index 0000000..d467d7f --- /dev/null +++ b/development/ldso/samename/lib.c @@ -0,0 +1,9 @@ +#include <stdio.h> + +#ifndef NAME +#define NAME __FILE_NAME__ +#endif + +void moose() { + puts(NAME " says moose"); +} diff --git a/development/ldso/samename/main.c b/development/ldso/samename/main.c new file mode 100644 index 0000000..6d6a8ea --- /dev/null +++ b/development/ldso/samename/main.c @@ -0,0 +1,36 @@ +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <string.h> + +void print_libso() { + FILE* m = fopen("/proc/self/maps", "r"); + assert(m); + + char line[256]; + while (fgets(line, sizeof(line), m)) { + if (strstr(line, "lib.so")) { + printf("%s", line); + } + } + fclose(m); +} + +int main(int argc, char* argv[]) { + for (int i = 1; i < argc; ++i) { + void* h = dlopen(argv[i], RTLD_LAZY | RTLD_GLOBAL); + if (!h) { + puts(dlerror()); + return 1; + } + + void (*next)() = dlsym(h, "moose"); + assert(next); + next(); + + // leak lib, we want to priint the mmap. + } + + print_libso(); + return 0; +} |