contributed by < ZhuMon
>
sysprog2020
quiz
1
MMM
= (d)
0x8080808080808080
is_ascii
藉由將 byte 與 0x80
做 and,確認 byte 的第一個 bit 是否為 1,藉此確認是否為 ASCII 的有效字元payload
(第 12 行),因此 mask 也要擴展,從只能判斷 1 個 byte 的 0x80
擴展到可以比對 8 個 byte 的 0x8080808080808080
為何使用 memcpy
?
根據 glibc 2.33 的 memcpy.c,將註解去掉後,如下
以下幾個 macro 會根據不同的架構而有所不同,在 glibc 的 generic memcopy.h 定義如下
memcpy
解釋OP_T_THRES
的記憶體,先將沒有對齊的資料複製完成後 (line17),便可以直接以 Page 作為單位快速的複製記憶體(PAGE_COPY_FWD_MAYBE
),接著以 word 作為單位複製剩下的記憶體,然後複製剩下的 bytememcopy.h
對於 BYTE_COPY_FWD(dst_bp, src_bp, nbytes)
的描述為
Copy exactly NBYTES bytes from SRC_BP to DST_BP,
without any assumptions about alignment of the pointers.
也就是說,BYTE_COPY_FWD
會從 src_bp
開頭逐一複製 nbytes
個 byte 到 dst_bp
的開頭 (另一個 macro BYTE_COPY_BWD
則是將來源位址和目標位址都視為結束位址來複製)
給予一個已知長度的字串,檢測裡頭是否包含有效的英文大小寫字母
查看 ASCII Table,可以知道英文大小寫字母所對應的 ASCII code 為 0x41~0x5A
, 0x61~0x7A
,以二進位表示如下
Char | Bin | Hex |
---|---|---|
A | 0100 0001 | 0x41 |
Z | 0101 1010 | 0x5A |
- | –– | - |
a | 0110 0001 | 0x61 |
z | 0111 1010 | 0x7A |
以
*
代表 don't care
觀察可知,英文字母的 ASCII code 前兩個 bit 必為 01,但是在 01** ****
的範圍中,{01000000
, 01011011 ~ 01100000
, 01111011 ~ 01111111
} 這三個區間內所對應的字元不是英文字母,總共有 12 個 ()
繼續觀察,將上述 12 個字元以第三個 bit 分成兩類,可以再歸納出三組
01*0 0000
01*1 1011
01*1 11**
hex | bin | hex | bin |
---|---|---|---|
0x40 | 0100 0000 | 0x60 | 0110 0000 |
0x5b | 0101 1011 | 0x7b | 0111 1011 |
0x5c | 0101 1100 | 0x7c | 0111 1100 |
0x5d | 0101 1101 | 0x7d | 0111 1101 |
0x5e | 0101 1110 | 0x7e | 0111 1110 |
0x5f | 0101 1111 | 0x7f | 0111 1111 |
因此只要 ASCII code 同時符合以下四點,便為英文字母
(char & 11000000) == 01000000
(char & 00011111) != 0
(char & 00011111) != 00011011
(char & 00011100) != 00011100
但是要在單個 byte 實作很簡單,多個 byte 同時判斷就很困難
TODO: 第五題似乎有較好的解決方法
2
已知 in
一定隸屬於 '0'
, '1'
, '2'
, …, '9'
及 'a'
, 'b'
, 'c'
, …, 'f'
(小寫) 及 'A'
, 'B'
, 'C'
, …, 'F'
(大寫) 這些字元。
預期 hexchar2val('F')
和 hexchar2val('f')
回傳 15
,且 hexchar2val('0')
回傳 0
,其他輸入都有對應的數值。
MASK
= 0x40
AAA
= 3
BBB
= 6
從結尾回推
從第 5 行的 return 值可以看到 (in + shift)
與 0xf
做 mask,因此 return 值只會在 0~15
之間。
0x30~0x39
,因此 shift
只要不會影響 in
的後 4 bit,便可以使數字部分達成目的,預計 shift
為 0x?0
0x61
(a
) 和 0x41
(A
) 對應到 10 (b'1010
),因此最簡單的想法就是將 shift
設為 9 (0x09
)明顯兩個規則矛盾,因此 shift
應該符合下述條件
shift
= 0x?0
, if in
{'0'
, '1'
, …, '9'
}shift
= 0x?9
, if in
{'A'
, …, 'F'
, 'a'
, …, 'f'
}判斷 letter
為何
從字面意義大概猜出 letter
代表英文字母,從選項來看,可以知道要將 in
的前 4 bit 的某些 bit 取出來
(a)
0x10
(b)
0x20
(c)
0x40
(d)
0x60
(e)
0x80
而可以判斷英文字母與數字的 bit 為第 2 個 bit 和第 4 個 bit
0011 xxxx
0100 xxxx
0110 xxxx
稍微瞄到下一行 (line 4),shift
會以 letter
來決定值,而我們的 shift
在 in
為數字時,不需要有值,因此應該以第 2 個 bit 作為 mask,也就是
MASK
= (c)
0x40
AAA
& BBB
由於前面已經知道在 in
為英文字母時,letter
為 b'0100 0000
,而要讓 shift
的後 4 bit 為 9 (b'0000 1001
),必須讓 letter
向左位移 3 位和向左位移 6 位,因此可以得到
AAA
= 3
BBB
= 6
3
為了得到餘數,function 必須返回
其中 為 的整數部分,也就是 quotient
,將 帶入下式
對照題目可知 (XXX / d) + 1 便是 264/d,而 XXX 最接近的選項便是 0xFFFFFFFFFFFFFFFF
> 關於為甚麼要先除以 d 再加 1,可以參考 @cmwchw 的解說
也就是說
設
由於
所以 可以捨去
4
判斷 n 是否被 d 整除
將 M 帶入後可得
…
將 n = 1 帶入,可以得到選項 (a) (b) (e) 都矛盾,因此只有可能是 或
試過所有值(0~232-1)後發現兩者依舊可以達成目的,懷疑等號右方只要小於 便可以達成目的
5
6