• R/O
  • SSH

posixpp: 提交

The main posixpp library and associated tests.


Commit MetaInfo

修订版5f78080a2b8856e6279379708ec5929d07571563 (tree)
时间2022-12-08 23:28:42
作者Eric Hopper <hopper@omni...>
CommiterEric Hopper

Log Message

Add some comments inspired by a ChatGPT session.

更改概述

差异

diff -r 901261d5fd16 -r 5f78080a2b88 pubincludes/syscalls/linux/x86_64/syscall.h
--- a/pubincludes/syscalls/linux/x86_64/syscall.h Tue Jan 11 08:03:33 2022 -0800
+++ b/pubincludes/syscalls/linux/x86_64/syscall.h Thu Dec 08 06:28:42 2022 -0800
@@ -6,9 +6,15 @@
66
77 namespace syscalls::linux::x86_64 {
88
9+// An emum class that represents system call numbers.
910 enum class call_id : ::std::uint16_t;
11+
12+// The fundamental type of a system call argument.
1013 using val_t = ::std::int64_t;
1114
15+// A wrapper that allows treating pointers and integers interchangeably.
16+// There are several comments to prompt the compiler to turn off warnings about
17+// bad conversions and use of `reinterpret_cast`.
1218 struct syscall_param {
1319 syscall_param(val_t v) noexcept : value(v) { } // NOLINT
1420 // NOLINTNEXTLINE
@@ -22,6 +28,10 @@
2228 val_t value;
2329 };
2430
31+
32+// The full 6 argument system call comments the inline assembly more thoroughly.
33+
34+// No argument system call (like `getpid`).
2535 inline val_t do_syscall(call_id callnum) noexcept
2636 {
2737 val_t retval;
@@ -34,6 +44,7 @@
3444 return retval;
3545 }
3646
47+// Single argument system call.
3748 inline val_t do_syscall(call_id callnum,
3849 syscall_param const &p1) noexcept
3950 {
@@ -47,6 +58,7 @@
4758 return retval;
4859 }
4960
61+// Two argument system call.
5062 inline val_t do_syscall(call_id callnum,
5163 syscall_param const &p1,
5264 syscall_param const &p2) noexcept
@@ -61,6 +73,7 @@
6173 return retval;
6274 }
6375
76+// Three argument system call.
6477 inline val_t do_syscall(call_id callnum,
6578 syscall_param const &p1,
6679 syscall_param const &p2,
@@ -76,6 +89,7 @@
7689 return retval;
7790 }
7891
92+// Four argument system call.
7993 inline val_t do_syscall(call_id callnum,
8094 syscall_param const &p1,
8195 syscall_param const &p2,
@@ -93,6 +107,7 @@
93107 return retval;
94108 }
95109
110+// Five argument system call.
96111 inline val_t do_syscall(call_id callnum,
97112 syscall_param const &p1,
98113 syscall_param const &p2,
@@ -112,6 +127,7 @@
112127 return retval;
113128 }
114129
130+// Six argument system call.
115131 inline val_t do_syscall(call_id callnum,
116132 syscall_param const &p1,
117133 syscall_param const &p2,
@@ -120,22 +136,55 @@
120136 syscall_param const &p5,
121137 syscall_param const &p6) noexcept
122138 {
139+ // Declare this, though when the assembly is inlined, it should just
140+ // magically be assigned to the `%rax` register.
123141 val_t retval;
142+
143+ // Declare alternate names for various registers and assign them the last few
144+ // arguments for the system call.
124145 register volatile val_t rp4 asm ("r10") = p4.value;
125146 register volatile val_t rp5 asm ("r8") = p5.value;
126147 register volatile val_t rp6 asm ("r9") = p6.value;
148+
149+ // This inline assembly is just a single instruction with lots of hints to
150+ // the compiler about how things should be set up before the instruction
151+ // executes. The goal is for the compiler to simply arrange for the
152+ // computations leading up to the instruction being emitted simply arrange
153+ // for the right values to be in place before it's executed.
127154 asm volatile (
128- "syscall\n\t"
129- :"=a"(retval)
130- :"a"(static_cast<::std::uint64_t>(callnum)), "D"(p1.value), "S"(p2.value), "d"(p3.value), "r"(rp4), "r"(rp5), "r"(rp6)
155+ "syscall\n\t" // The single instruction
156+
157+ :"=a"(retval) // The `%rax` register should be put into `retval` after the
158+ // instruction is executed (i.e. retval will simply end up
159+ // being another name for `%rax`.
160+
161+ // Declaring various input registers and where they come from.
162+ :"a"(static_cast<::std::uint64_t>(callnum)), // %rax contains callnum
163+ "D"(p1.value), // %rdi contains p1.value
164+ "S"(p2.value), // %rsi contains p2.value
165+ "d"(p3.value), // %rdx contains p3.value
166+ "r"(rp4), // What rp4 means has already been declared above.
167+ "r"(rp5), // What rp5 means has already been declared above.
168+ "r"(rp6) // What rp6 means has already been declared above
169+
170+ // Declaring what regsiters will no longer have usable values after the
171+ // instruction finishes. Also declaring that the instruction may result
172+ // in random places in memory having been changed.
131173 :"%rcx", "%r11", "memory"
132174 );
175+
176+ // This should not result in any instruction being emitted because %rax is
177+ // where integer return values are stored in the x86_64 abi anyway.
133178 return retval;
134179 }
135180
136181
182+// This is where errno will go now, or the system call result.
137183 using expected_t = ::posixpp::expected<val_t>;
138184
185+// This effectively creates 6 new functions that will each call the appropriate
186+// `do_syscall` overload. They then check for an error return and set up
187+// `::posixpp::expected` in the correct way for an error vs. normal return.
139188 template <typename... T>
140189 expected_t
141190 syscall_expected(call_id callnum, T &&... args) noexcept
@@ -347,6 +396,9 @@
347396 };
348397
349398 namespace priv_ {
399+// Just a bunch of tests to make sure the enum is being set up as expected.
400+// Designed to catch people inserting values into the enum without paying
401+// attention to how the compiler is assigning integers to the various members.
350402 inline void compiletime_tests()
351403 {
352404 static_assert(static_cast<::std::uint16_t>(call_id::sendfile) == 40);
Show on old repository browser