---
# System prepended metadata

title: 先決測驗
tags: [2021 Summer - Linux kernel]

---

# 先決測驗
###### tags: `2021 Summer - Linux kernel`
:::warning
依據指定格式，標注 GitHub 帳號名稱
:notes: jserv
:::
Github account: [demonsome](https://github.com/demonsome/linux2021_projects.git)

[先決測驗題目連結](https://hackmd.io/@sysprog/linux2021-summer/https%3A%2F%2Fhackmd.io%2F%40sysprog%2Flinux2021-summer-quiz)

## 測驗 $\alpha$ 
延伸問題:

**1. 舉出 Linux 核心原始程式碼裡頭 bit rotation 的案例並說明:**

**ANS:**
 在Linux核心之中的[bitops.h](https://github.com/torvalds/linux/blob/master/tools/include/linux/bitops.h)之中，我們可以找到bit rotation的程式碼如下:
```clike=
/**
 * rol32 - rotate a 32-bit value left
 * @word: value to rotate
 * @shift: bits to roll
 */
static inline __u32 rol32(__u32 word, unsigned int shift)
{
	return (word << shift) | (word >> ((-shift) & 31));
}
```
此函式為巨集定義，故`__u32`會在編譯後被取代為32bits的資料型態，變數**word**為32bits。這是實作32bits的向左位元旋轉，位移量為變數**shift**。舉例來說，當**word** = 0xABCDEF12, **shift** = 4 時，此函式應回傳 0xBCDEF12A 。

因此，實作上只要將word向左位移**shift**個bits，以此例來說是0xABCDEF12向左位移4個bits成為0xBCDEF120，並和word向右位移(32-**shift**)個bits，即0x0000000A，兩者再進行AND bitwise操作即可得到結果。

但為確保(32-**shift**)在大於31以及小於0時，仍可以正確運作。故寫成((-**shift**) & 31)，此操作類似mod 32，使數值可以落在0到31之間。


**2. x86_64 指令集具備 rotr 和 rotl 指令，下述(測驗 $\alpha$ ) C 程式碼經過編譯器最佳化 (例如使用 gcc) 後，能否運用到這二個指令呢？**
```c=
#include <stdint.h>
  
#define __DECLARE_ROTATE(bits, type)                   \
    static inline type rotl##bits(const type v, int c) \
    {                                                  \
        const int mask = (bits) - (1);                 \
        c &= mask;                                     \
                                                       \
        return (v << c) | (LLL);                      \
    }                                                  \
                                                       \
    static inline type rotr##bits(const type v, int c) \
    {                                                  \
        const int mask = (bits) - (1);                 \
        c &= mask;                                     \
                                                       \
        return (v >> c) | (RRR);                      \
    }

#define DECLARE_ROTATE(bits) __DECLARE_ROTATE(bits, uint##bits##_t)
```
**ANS:**

一般來說，若gcc可認得pattern: `(x << n) | (x >> (bits - n))`，則在最佳化時可直接將上述程式碼編譯成rotr 和 rotl指令，以減少指令數，增加處理器執行效能。

但是前提需滿足`0<n<bits`，否則編譯時，編譯器對於這些未定義的行為，會直接轉成 negl, shrl, sall, orl...等多個指令，而非rotr 和 rotl指令。詳細資訊可參考:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57157
## 測驗 $\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 MMM;       
    }
    return (((sz + mask) / alignment) * alignment);
}
```
此函式是將參數**sz**向上進位至參數**alignment**的倍數後回傳，若**alignment**是2的冪次方，則套用一個比較快速的方式(bitwise operation)回傳，否則使用除法的方式向上進位。

由於數位邏輯的基本運算中，邏輯運算如: AND, OR, NOT, shift 等bitwise operation操作是遠比除法快很多的。故將2的冪次方的情況獨立出來處理。

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

在linux的header file [align.h](https://github.com/torvalds/linux/blob/master/include/linux/align.h)中定義了向上對齊至2的冪次方的巨集，如下:
```c=
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_ALIGN_H
#define _LINUX_ALIGN_H

#include <linux/const.h>

/* @a is a power of 2 value */
#define ALIGN(x, a)		__ALIGN_KERNEL((x), (a))
#define ALIGN_DOWN(x, a)	__ALIGN_KERNEL((x) - ((a) - 1), (a))
#define __ALIGN_MASK(x, mask)	__ALIGN_KERNEL_MASK((x), (mask))
#define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
#define PTR_ALIGN_DOWN(p, a)	((typeof(p))ALIGN_DOWN((unsigned long)(p), (a)))
#define IS_ALIGNED(x, a)		(((x) & ((typeof(x))(a) - 1)) == 0)

#endif	/* _LINUX_ALIGN_H */
```

而我們又可以在`/include/linux/netfilter/x_tables.h`中發現`__ALIGN_KERNEL`的蹤跡，巨集如下:
```c=
/* this is a dummy structure to find out the alignment requirement for a struct
 * containing all the fundamental data types that are used in ipt_entry,
 * ip6t_entry and arpt_entry.  This sucks, and it is a hack.  It will be my
 * personal pleasure to remove it -HW
 */
struct _xt_align {
	__u8 u8;
	__u16 u16;
	__u32 u32;
	__u64 u64;
};

#define COMPAT_XT_ALIGN(s) __ALIGN_KERNEL((s), __alignof__(struct _compat_xt_align))
```

由於在gcc及XL C/C++中，`__alignof__`讓你可以了解一個物件是如何被對齊的，在此應用中，假設結構`_compat_xt_align`需對齊到a個bytes的邊界，`COMPAT_XT_ALIGN(s)`將回傳一個讓參數s可以向上對齊的一個a的倍數，且a是2的冪次方。如此，可以確保物件在記憶體位置中被正確的擺放，而沒有被錯誤覆寫的狀況發生。


