Showing posts with label coding_trick. Show all posts
Showing posts with label coding_trick. Show all posts

Mar 25, 2026

[intel] 5-level paging (LA57) affects MSB pointer tagging

Resource:
https://en.wikipedia.org/wiki/Intel_5-level_paging

The adoption of 5-level paging (also known as LA57) allows the virtual address space to expand from the traditional 48 bits (256 TiB) to 57 bits (128 PiB).




In 5-level paging (LA57), the "free" or unused bits are indeed bits 57 through 63, which totals 7 bits. However, there is a catch: those bits aren't truly "free" for software to store random data (like tags or metadata) unless a specific hardware feature like Intel LAM (Linear Address Masking) or AMD UAI (Upper Address Ignore) is enabled.

The Breakdown of the 64-bit Address

Here is how the 64 bits are partitioned in a 5-level paging system:

  • Bits 0–11: Page Offset (4 KB boundaries).
  • Bits 12–56: The actual translation bits used by the five levels of page tables 9 x 5 = 45 bits
  • Bits 57–63: The 7 unused bits.


The "Canonical" Constraint

The CPU enforces a rule called Canonical Form. For an address to be valid:
Bits 57 through 63 must be an exact copy of bit 56.
If bit 56 is 0, then bits 57–63 must all be 0.
If bit 56 is 1, then bits 57–63 must all be 1.

If software tries to use an address where those 7 bits are "dirty" (containing random data), the CPU will trigger a General Protection Fault (#GP). This is why programmers can't simply use those 7 bits for pointers without the masking features mentioned above.

Jul 28, 2024

[C++] tag pointer

Reference:
Storing data in pointers

#include <cstddef>
#include <cstdint>
#include <iostream>


enum ListType {
  kNone,
  kReady,
  kDeleting,
};


static constexpr uintptr_t kListTypeMask = 0b11;
static constexpr uintptr_t kCleanPtrMask = ~kListTypeMask;

struct Tree;

struct Node{
  void set_list_type(ListType list_type) {
    uintptr_t t = static_cast<uintptr_t>(list_type);
    uintptr_t v = ptr_and_list_type_ & kCleanPtrMask;
    ptr_and_list_type_ = (v | t);
  }

  ListType list_type() const {
    return static_cast<ListType>(ptr_and_list_type_ & kListTypeMask);
  }

  void set_prev_next_ptr(Node** p) {
    uintptr_t t = ptr_and_list_type_ & kListTypeMask;
    uintptr_t v = reinterpret_cast<uintptr_t>(p);
    ptr_and_list_type_ = (v | t);
  }

  Node** prev_next_ptr() const {
    return reinterpret_cast<Node**>(ptr_and_list_type_ & kCleanPtrMask);
  }

  Tree* tree_ = nullptr;
  Node* parent_ = nullptr;
  Node* next_ = nullptr;
  uintptr_t ptr_and_list_type_ = 0;
};

struct Tree{
  void MarkReady(Node* p) {
    p->next_ = ready_;
    p->set_prev_next_ptr(&ready_);

    if (ready_ != nullptr) {
      ready_->set_prev_next_ptr(&p->next_);
    }

    ready_ = p;
    p->set_list_type(kReady);
  }
 
  int padding;
  Node* ready_ = nullptr;
};


int main() {
  // Print 8 since padding is type of int occupies 8 bytes.
  std::cout << "offset of ready_: " <<
    reinterpret_cast<void*>(&((Tree*)0)->ready_) << "\n";

  Tree* tree = new Tree{};
  std::cout << "tree: " << reinterpret_cast<void *>(&tree) << "\n";
  std::cout << "tree offset of ready: " <<
    reinterpret_cast<void *>(&tree->ready_) << "\n";

  Node p;
  p.tree_ = tree;
  tree->MarkReady(&p);
  std::cout << reinterpret_cast<void *>(p.prev_next_ptr()) << "\n";
}

MSB tagging vs. LSB tagging

Feb 25, 2014

[c][c++][note] Duff device

A Reusable Duff Device
#define DUFF_DEVICE_8(aCount, aAction) \
do { \
	int count_ = (aCount); \
	int times_ = (count_ + 7) >> 3; \
	
    switch (count_ & 7){ \
		case 0: do { aAction; \
		case 7: aAction; \
		case 6: aAction; \
		case 5: aAction; \
		case 4: aAction; \
		case 3: aAction; \
		case 2: aAction; \
		case 1: aAction; \
		} while (--times_ > 0); \
	} \
} while (0)
Or just use template and lambda:
#include <iostream>                                                                       
                                                                                          
                                                                                          
template<typename INPUT>                                                                  
void duffDevice(INPUT process, int count)                                                 
{                                                                                         
   int n = (count + 7) >> 3;                                                              
   switch(count % 8)                                                                      
   {                                                                                      
      case 0: do { process();                                                             
      case 7: process();                                                                  
      case 6: process();                                                                  
      case 5: process();                                                                  
      case 4: process();                                                                  
      case 3: process();                                                                  
      case 2: process();                                                                  
      case 1: process();                                                                  
              } while(--n >0);                                                            
   };                                                                                     
}                                                                                         
                                                                                          
                                                                                          
int main()                                                                                
{                                                                                         
   duffDevice([]{std::cout << "poll data" << std::endl;}, 108);                           
}
Reference: Macro Note Clifford's Device GOTO statement Switch statement

Sep 8, 2012

[Macro][NOTE]

Macros
Variadic Macros
Tips on writing C macros

FIX:
Use ntohs(3) instead of ::ntohs(3).

The alternative fix

Add the following line after your includes:

#undef ntohs
Excerpt from "Tips on writing C macros"

RULE 1: Always write your multiline macros using this pattern:
    #define MYMACRO \
    do { \
       macro definition here \
    } while (0)
The only trouble you might get with this, is some smart-a$$ code analyzer screaming about a 'constant expression in do-while condition'. That's usually easy to turn off by adding some comment-directive to your macro definition. Just make sure you only use /*C-style comments*/ in macros ;-) RULE 2: Always surround macro arguments with parentheses inside the macro body.
    #define MYMACRO(a,b,c) \
    do { \
       (a) = (b) + (c); \
       (b) = (c)*2; \
    } while (0)
it's better to use
#define REGISTER_CONTEXT_FACTORY_FUNCTION(fn...)
then
REGISTER_CONTEXT_FACTORY_FUNCTION((lambda));
1) Developer Experience (Ergonomics):
Forcing developers to write extra double parentheses (( ... ))
is awkward and prone to human error.
2) Hard-to-Debug Compiler Errors:
If a developer forgets the extra parentheses, they get very
confusing preprocessor errors (e.g., "macro passed 2 arguments but takes 1"),
which are difficult to trace back to a missing set of parentheses.
3) Syntactic Cleanliness:
Using fn... allows the registration to look like a native C++
function invocation (REGISTER_CONTEXT_FACTORY_FUNCTION([](...) { ... })),
keeping the boilerplate minimal and clean.


RULE 3: Keep your macros SHORT. Don't write 50-line macros, because when the time comes to chase down some bug you will soon find out that the only debugger that could step into macro definitions (SoftICE) is out of business. To the best of my knowledge, even WinDBG, the Windows kernel debugger, cannot step into macros. So, keep'em short. RULE 4: Be very careful when trying to use macros for speed optimizations (i.e. save a function call). I have seen even senior programmers get it wrong, because they didn't realize that passing MyArray[x+3] as a macro argument would lexically copy this expression in multiple locations in the macro expansion, causing the generated code to needlessly evaluate MyArray[x+3] again and again and again. Always have someone else, preferably more experienced than yourself, check these 'optimizations' with you.

Mar 23, 2012

[C++][NOTE] Alignment

[c][c++][NOTE] Clifford's Device

A very interesting discussion.

C compiler thinks different than us(in Chinese)

Clifford's Device


#include <stdio.h>
#define DEBUG 1
#define DBG( ... ) \
    if (DEBUG) {  __VA_ARGS__; }
int main(int argc, char *argv[]) {
    char *num;
    switch (argc - 1) {
             case  0: num =  "zero";
        DBG( case  1: num =   "one"; )
        DBG( case  2: num =   "two"; )
        DBG( case  3: num = "three"; )
        DBG( default: num =  "many"; )
        while (--argc)
            printf("%s ", argv[argc]);
        printf("\nArgument count: %s\n", num);
        break;
    }
    return 0;
}
//-----------
#include 

int main(int argc, char **argv)
{
        int num;

        if (argc != 3) {
                fprintf(stderr, "Usage: %s {BIN|OCT|DEC|HEX|STR} {ARG}\n", argv[0]);
                return 1;
        }

        if (!strcmp(argv[1], "BIN")) {
                num = strtol(argv[2], NULL, 2);
                goto number_mode;
        } else
        if (!strcmp(argv[1], "OCT")) {
                num = strtol(argv[2], NULL, 8);
                goto number_mode;
        } else
        if (!strcmp(argv[1], "DEC")) {
                num = strtol(argv[2], NULL, 10);
                goto number_mode;
        } else
        if (!strcmp(argv[1], "HEX")) {
                num = strtol(argv[2], NULL, 16);
                goto number_mode;
        } else
        if (!strcmp(argv[1], "STR")) {
                printf("Called with string argument: '%s'\n", argv[2]);
        } else {
                printf("Called unsupported mode: '%s'\n", argv[1]);
        }

        /* Clifford's Device */
        if (0) {
number_mode:
                printf("Called with numeric argument: %d\n", num);
        }

        return 0;
}

//----------
#include 

int main(int argc)
{
        char *num;

        switch (argc-1)
        {
        if (0) { case  0: num = "zero";  }
        if (0) { case  2: num = "two";   }
        if (0) { case  3: num = "three"; }
        if (0) { case  4: num = "four";  }
        if (0) { case  5: num = "five";  }
        if (0) { default: num = "many";  }
                printf("Called with %s arguments.\n", num);
                break;
        case 1:
                printf("Called with one argument.\n");
        }

        return 0;
}

As we should notice how switch is implemented in the compiler.
It's actually "goto". Reference: Duff's_device

Mar 7, 2012

[UNIX Programming] tips

1. Not to include a representation dependency in the printf()
pid_t arg;
printf("%ld",(long) arg);

Feb 26, 2012

[C++ / C Programming] Tips

1. How to get the maximum of an unsigned value.
Use cast.
static_cast<size_type>(-1);
size_type could be a unsigned type.
that's it!

2.Writing C/C++ Macros: Rules, Tricks and Hints

Linux Kernel巨集do{...}while(0)的撰寫

《Linux kernel coding style》 => Documentation/CodingStyle