wshibin's Technical Blog

website·Indexed 29 days ago

https://wshibin.github.io

A collection of technical notes and analyses covering systems programming, C/C++, RISC-V assembly, and Linux performance optimization. Includes deep dives into spdlog, musl libc, and LVGL V7.11.0 source code, as well as guides on WinDbg, GoogleTest, and Node.js.

Tokens
449.4K
Snippets
2K
Records
2.8K
Agent score
74%

What's inside wshibin

  1. Overview of CLAUDE.md for Claude Code

    CLAUDE.md is a project context file located in the root directory of a project. It serves as the 'brain' or initial cognitive model for Claude Code, providing the AI with essential project context, architecture, and conventions immediately upon starting a session. Unlike a README.md (which is written for humans), CLAUDE.md is written specifically for the AI to ensure consistent code output, reduce errors, and save context window usage by preventing the AI from having to rediscover project patterns via tools in every session.
  2. Overview of RISC-V Floating-Point Extensions (F and D)

    RISC-V implements floating-point support through layered extensions based on the IEEE 754 standard:

    • F Extension: Provides 32 single-precision (32-bit) floating-point registers (f0-f31) and associated load/store, arithmetic, comparison, and conversion instructions.
    • D Extension: Extends registers to 64-bit width for double-precision. It depends on the F extension. When D is present, single-precision values are stored in the lower 32 bits, with the upper 32 bits set to NaN-boxing (all 1s).
    • Instruction Suffixes: Instructions ending in .s denote single-precision operations; those ending in .d denote double-precision operations.
  3. Overview of Rust Basic Types

    Rust provides a variety of basic types categorized by their purpose and memory layout. Key types include signed and unsigned integers, floating-point numbers, booleans, Unicode characters, compound types (tuples, arrays), and heap-allocated or reference types (Vec, String, Box, slices).
    CategoryTypesSize
    Signed Integersi8, i16, i32, i64, i128, isize8/16/32/64/128/ptr width
    Unsigned Integersu8, u16, u32, u64, u128, usize8/16/32/64/128/ptr width
    Floatsf32, f6432/64 bits
    Booleanbool1 byte
    Characterchar4 bytes (Unicode scalar)
    Tuple(T1, T2, ...)Sum of elements
    Array[T; N]N * size_of::<T>()
    VectorVec<T>3 words (ptr, len, cap)
    Slice&[T], &mut [T]2 words (ptr, len)
    String Slice&str, &mut str2 words (ptr, len)
    Owned StringString3 words (ptr, len, cap)
    Reference&T, &mut T1 word (pointer)
    BoxBox<T>1 word (pointer)
    Raw Pointer*const T, *mut T1 word
    Function Pointerfn(T1, T2) -> R1 word
  4. Overview of Rust I/O Trait Hierarchy

    Rust's I/O system is built around three core traits that provide a unified interface for files, network connections, memory buffers, and terminals:

    • Read: For byte-oriented input.
    • Write: For byte-oriented output.
    • BufRead: For buffered input (inherits from Read), enabling line-based reading.

    Common implementations include:

    • Read: File, TcpStream, Stdin, Cursor<&[u8]>, &[u8].
    • BufRead: BufReader<R>, StdinLock, Cursor<&[u8]>.
    • Write: File, TcpStream, Stdout, Stderr, Vec<u8>, BufWriter<W>, Cursor<&mut [u8]>.
    use std::io::prelude::*;
    use std::io::{self, Read, Write, ErrorKind};
  5. Overview of RISC-V Pseudo-Instructions

    Pseudo-instructions are high-level mnemonics provided by the assembler to improve readability, hide complexity, and ensure portability. They are not recognized by the CPU hardware; instead, the assembler transparently translates each pseudo-instruction into one or more 'hard' instructions (machine code) before outputting the final binary. This process is deterministic and can be inspected using tools like gcc -S or objdump -M no-aliases.
  6. Overview of RISC-V RV64I Register File

    The RV64I architecture provides 32 general-purpose registers (x0-x31), each 64 bits wide. Registers are the fastest storage in the CPU with zero-cycle latency. The Program Counter (PC) is a separate 64-bit register that tracks the current instruction address; it cannot be accessed directly like general-purpose registers and is modified only via jump/branch instructions or AUIPC.
  7. Overview of CMake and its toolset

    CMake is an open-source, cross-platform build system generator. It does not build the software itself but generates native makefiles and workspaces for various build systems (such as Make, Ninja, Visual Studio, and Xcode) based on platform-independent configuration files.

    The CMake family consists of several key tools:

    • CMake: The primary tool for configuration and build system generation.
    • CTest: Used for testing the software.
    • CPack: Used for packaging the software.
  8. Overview of Windows User Mode and Kernel Mode architecture

    Windows architecture is split into two primary modes:

    User Mode Components:

    • User Processes: Standard applications (e.g., notepad.exe).
    • Subsystem DLLs: Implement official Windows APIs (e.g., kernel32.dll, user32.dll, gdi32.dll).
    • NTDLL.DLL: The lowest layer of user mode; implements Native APIs and handles the transition to kernel mode. Also manages the heap and image loader.
    • Service Processes: Processes communicating with the Service Control Manager (services.exe).

    Kernel Mode Components:

    • Executive (NtOskrnl.exe): Upper layer containing managers for objects, memory, I/O, PnP, power, and configuration.
    • Kernel: Core time-sensitive functions including thread scheduling, interrupt/exception dispatching, and synchronization (mutexes/semaphores).
    • Device Drivers: Loadable modules executing in kernel mode.
    • Win32k.sys: Kernel-mode component for the Windows subsystem (UI and GDI).
    • HAL (Hardware Abstraction Layer): Hides hardware details (interrupt controllers, DMA) from drivers.
  9. Overview of Memory-Mapped Files (MMF) in Windows

    Memory-Mapped Files (MMF), known as 'Sections' in the kernel, allow an application to map a disk file's contents directly into its virtual address space. This enables file access via standard pointers instead of repeated ReadFile and WriteFile calls. Key advantages include:

    • No need for manual buffer allocation or repeated I/O function calls.
    • Ability to use standard memory functions like memcpy and memset on file data.
    • Improved performance via OS-managed caching.
    • Native support for high-performance Inter-Process Communication (IPC) through shared memory.
  10. Overview of the Windows I/O System Architecture

    The Windows I/O system abstracts access to both physical and logical devices. User-mode processes interact with the system via Windows APIs. At the kernel level, the I/O Manager converts these requests into I/O Request Packets (IRPs), which are then passed to the appropriate device driver (e.g., an NTFS driver for files). While kernel-level I/O is inherently asynchronous, the I/O Manager can handle synchronization for the caller if a synchronous call is requested.
  11. Overview of overloadable operators in Rust

    In Rust, operator overloading is achieved by implementing specific traits from std::ops or std::cmp. Rust does not allow the creation of new operators or the overloading of logic operators like &&, ||, or the assignment operator =. When an operator is used (e.g., a + b), Rust desugars it into a trait method call (e.g., a.add(b)).
    CategoryOperatorTraitMethod
    Unary-xstd::ops::Negneg(self) -> Output
    Unary!xstd::ops::Notnot(self) -> Output
    Arithmetica + bstd::ops::Addadd(self, rhs) -> Output
    Arithmetica - bstd::ops::Subsub(self, rhs) -> Output
    Arithmetica * bstd::ops::Mulmul(self, rhs) -> Output
    Arithmetica / bstd::ops::Divdiv(self, rhs) -> Output
    Arithmetica % bstd::ops::Remrem(self, rhs) -> Output
    Bitwisea & bstd::ops::BitAndbitand(self, rhs) -> Output
    Bitwisea | bstd::ops::BitOrbitor(self, rhs) -> Output
    Bitwisea ^ bstd::ops::BitXorbitxor(self, rhs) -> Output
    Bitwisea << bstd::ops::Shlshl(self, rhs) -> Output
    Bitwisea >> bstd::ops::Shrshr(self, rhs) -> Output
    Compound Assigna += bstd::ops::AddAssignadd_assign(&mut self, rhs)
    Compound Assigna -= bstd::ops::SubAssignsub_assign(&mut self, rhs)
    Compound Assigna *= bstd::ops::MulAssignmul_assign(&mut self, rhs)
    Comparisona == bstd::cmp::PartialEqeq(&self, &rhs) -> bool
    Comparisona != bstd::cmp::PartialEqne(&self, &rhs) -> bool
    Comparisona < bstd::cmp::PartialOrdlt(&self, &rhs) -> bool
    Comparisona <= bstd::cmp::PartialOrdle(&self, &rhs) -> bool
    Comparisona > bstd::cmp::PartialOrdgt(&self, &rhs) -> bool
    Comparisona >= bstd::cmp::PartialOrdge(&self, &rhs) -> bool
    Indexinga[i]std::ops::Indexindex(&self, idx) -> &Output
    Indexinga[i] = vstd::ops::IndexMutindex_mut(&mut self, idx) -> &mut Output