# linux2021: [e361](https://github.com/e361) :::warning 注意細節! :notes: jserv ::: ## 測驗 $\alpha$-1 舉出linux核心原始程式碼裡頭的案例並說明 >linux kernel裡的 <bitop.h> 定義的幾個circular shift macro,包含 ```c static inline rol64(__u64 word, unsigned int shift) static inline ror64(__u64 word, unsigned int shift) static inline rol32(__u32 word, unsigned int shift) static inline ror32(__u32 word, unsigned int shift) static inline rol16(__u16 word, unsigned int shift) ror16(...), rol8(...), ro8(...) ``` * 這些聚集根據操作的位元數不同,做出往右/往左的 circular shift 共同的操作為: word >> (shift & x) | word << (-shift & x) [往左循環位移] word << (shift & x) | word >> (-shift & x) [往右循環位移] 其中 x 是操作對象的位元數在少1 * shift 為主要位移的數量, 而 -shift 則是反方向需要補上去的 跟 x 做 AND bitwise operation 是為了消除符號 最後 OR bitwise operation 將個別部份連接起來 ---------------------------------------------------------------------- ## 測驗$\alpha$-2 x86-64具備rotr和rotl指令,上述C程式碼經過編譯器最佳化後,能否運用到這兩個指令? C code ```c= int main(void){ int ch = 0b11010001; printf("%d\n", rotr8(ch, 2)); printf("%d\n", rotl8(ch, 1)); return 0; } ``` >使用gcc編譯的結果: :::spoiler ```shell=1 $gcc --version gcc (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0 $gcc -S -o rotate.s rotate.c 節錄自rotate.s rotl8: .LFB2: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, %eax movl %esi, -24(%rbp) movb %al, -20(%rbp) movl $7, -4(%rbp) movl -4(%rbp), %eax andl %eax, -24(%rbp) movzbl -20(%rbp), %edx movl -24(%rbp), %eax movl %eax, %ecx sall %cl, %edx movl %edx, %eax movl %eax, %esi movzbl -20(%rbp), %edx movl -24(%rbp), %eax negl %eax andl -4(%rbp), %eax movl %eax, %ecx sarl %cl, %edx movl %edx, %eax orl %esi, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE2: .size rotl8, .-rotl8 .type rotr8, @function rotr8: .LFB3: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, %eax movl %esi, -24(%rbp) movb %al, -20(%rbp) movl $7, -4(%rbp) movl -4(%rbp), %eax andl %eax, -24(%rbp) movzbl -20(%rbp), %edx movl -24(%rbp), %eax movl %eax, %ecx sarl %cl, %edx movl %edx, %eax movl %eax, %esi movzbl -20(%rbp), %edx movl -24(%rbp), %eax negl %eax andl -4(%rbp), %eax movl %eax, %ecx sall %cl, %edx movl %edx, %eax orl %esi, %eax popq %rbp .cfi_def_cfa 7, 8 ret ``` ::: * 根據編譯完的結果,編譯器把需要位移的bytes數做位置偏移,並沒有利用到 ROR,ROL 而是利用SAR,SAL 算術位移運算來達到等同的效果 ---------------------------------------------------------- ## 測驗$\beta$-1 說明上述程式碼的原理 ```c= #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非2^次方時,其實是在做ceiling的動作, * (sz + mask) / alignment == $\lceil$sz / alignment$\rceil$ * 在alignment是2^次方部份, &~mask指的是說對所需的總對齊數求商,因為mask是alignemnt的餘數,而(sz+mask)指的是說原本有沒有剩餘無法被alignment整除的部份,如果有得補回去 :::warning power of 2 的翻譯是「2 的冪」 :notes: jserv ::: --- ## 測驗$\beta$-2 Linux kernel 的 align-up alike macro? * some linux kernel align macro ```c= #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a)-1) #define __ALIGN_MASK(x, mask) (((x) + (mask))&~(mask)) ``` * eg. ALIGN(16, 4) ---> 16 * 更具通用性 * 有保護的功能???