aboutsummaryrefslogtreecommitdiffhomepage
path: root/development
diff options
context:
space:
mode:
authorjohannst <johannst@users.noreply.github.com>2024-04-10 19:37:02 +0000
committerjohannst <johannst@users.noreply.github.com>2024-04-10 19:37:02 +0000
commit269caa8ae18eb33e1286e4c21d434ea07228a619 (patch)
treeb9c0ae7bf44a6873adc4c9da9204de2bdf4a1de1 /development
parent92fc0e8e46352a593c3ce7f87292ee1c4ee4c4e4 (diff)
downloadnotes-269caa8ae18eb33e1286e4c21d434ea07228a619.tar.gz
notes-269caa8ae18eb33e1286e4c21d434ea07228a619.zip
deploy: ae498864bb638e597b589c52ff27237835625281
Diffstat (limited to 'development')
-rw-r--r--development/c++.html106
-rw-r--r--development/c++/Makefile5
-rw-r--r--development/c++/concepts-20.cc105
-rw-r--r--development/ld.so.html3
-rw-r--r--development/ldso/samename/Makefile13
-rw-r--r--development/ldso/samename/lib.c9
-rw-r--r--development/ldso/samename/main.c36
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&lt;B&gt;::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&lt;typename T&gt;
+using Alias = T;
+
+void print(int);
+
+// -- CONCEPTS &amp; REQUIRE EXPRESSIONS -------------------------------------------
+
+// Simple concept from a type trait.
+template&lt;typename T, typename U&gt;
+concept Same = std::is_same&lt;T, U&gt;::value;
+
+// Simple requirement concepts.
+template&lt;typename T&gt;
+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&lt;typename T&gt;
+concept TraitTypes = requires(T t) {
+ // T must have a type definition inner.
+ typename T::inner;
+ // Type alias must exist.
+ typename Alias&lt;T&gt;;
+};
+
+// Compound requirement concepts.
+template&lt;typename T&gt;
+concept TraitFns = requires(T t, const T c) {
+ // void T::foo() must exist.
+ { t.foo() };
+ // bool T::bar() const; must exist.
+ { c.bar() } -&gt; Same&lt;bool&gt;;
+ // static void T::stat(); must exist.
+ { T::stat() } -&gt; Same&lt;int&gt;;
+};
+
+// Nested requirement concepts.
+template&lt;typename T&gt;
+concept TraitNested = requires(T t) {
+ // Must satisfy other concepts.
+ requires TraitTypes&lt;T&gt;;
+ requires TraitFns&lt;T&gt;;
+};
+
+// -- REQUIRE EXPRESSIONS ------------------------------------------------------
+
+// Require expressions can be evaluated to booleans.
+template&lt;typename T&gt;
+static constexpr bool IsTraitFns = requires { requires TraitFns&lt;T&gt;; };
+
+// Require expressions can also be used in static assertions.
+static_assert(requires { requires Same&lt;int, int&gt;; });
+static_assert(!requires {
+ typename Alias&lt;int&gt;;
+ requires Same&lt;int, void&gt;;
+});
+
+// -- TESTS --------------------------------------------------------------------
+
+static_assert(requires { requires TraitAddAndPrint&lt;int&gt;; });
+
+struct FnTypeGood {
+ using inner = int;
+};
+struct FnTypeBad {};
+static_assert(requires { requires TraitTypes&lt;FnTypeGood&gt;; });
+static_assert(!requires { requires TraitTypes&lt;FnTypeBad&gt;; });
+
+struct FnGood {
+ void foo();
+ bool bar() const;
+ static int stat();
+};
+struct FnBad {};
+static_assert(requires { requires TraitFns&lt;FnGood&gt;; });
+static_assert(!requires { requires TraitFns&lt;FnBad&gt;; });
+
+struct NestedGood : FnTypeGood, FnGood {};
+struct NestedBad1 : FnGood {};
+struct NestedBad2 : FnTypeGood {};
+static_assert(requires { requires TraitNested&lt;NestedGood&gt;; });
+static_assert(!requires { requires TraitNested&lt;NestedBad1&gt;; });
+static_assert(!requires { requires TraitNested&lt;NestedBad2&gt;; });
+</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 &lt;cassert&gt;
#include &lt;cstdio&gt;
#include &lt;new&gt;
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;
+}