Try   HackMD

測驗α

α - 1 解釋上述程式碼運作原理

測驗β

β - 1 解釋程式碼的運作行為

#include <stdint.h>

static inline uintptr_t align_up(uintptr_t sz, size_t alignment)
{
    uintptr_t mask = alignment - 1;
    if ((alignment & mask) == 0) {  /* power of two? */
        return (sz + mask ) & (~mask); 
    }
    return (((sz + mask) / alignment) * alignment);
}

程式的目的是針對給定的 alignment 數值,輸出大於等於 alignment 的記憶體對齊地址。但當 alignment 為二的冪次時可以透過數字的特性來作

二的冪次的特性為

  • least significant bit 必定為 0
  • 除了 least significant bit 外只會有一個位元為1

如下:

0000 0010 //2
0000 0100 //4
0000 1000 //8
0001 0000 //16
0000 0000
...
...

接著可以透過可以透過 sz + mask 來判斷是否 sz 是否需要向上對齊。 若 mask 對應的位元任一數為 1 則代表 sz 許要向上取 alignment 的倍數,反之則不需要。

相加之後需要透過與 ~mask 做 && 來清除多餘的位元。
舉例來說假設輸入的 sz = 17, alignment = 4 。 預期輸出的數值為 20 。

17 的二位元表示為

0001 0001

4 的二位元表示則為

0000 0100

mask

0000 0011

17 + mask

 0001 0001
+0000 0011
=0001 0100

(17 + mask) & ~mask

 0001 0100
&1111 1100
=0001 0100

可以看到結果如同預期。

β - 2 在 Linux 核心原始程式碼找出類似 align_up 的程式碼,並舉例說明其用法

從 Linux 的 const.h 可以看到 __ALIGN_KERNEL(x, a) 這個 macro 定義另一個 macro __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)

__ALIGN_KERNEL_MASK 本身定義的函式則為 (((x) + (mask)) & ~(mask))

相關的用法可以在 ioam6_parser.cstatic int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h, const struct ioam_config cnf) 中看到透過 __ALIGN_KERNEL 將 len 以 4 向上對齊。

...
...
if (ioam6h->type.bit22) {
		len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
		aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
...
...

測驗γ - 1