memcpy函式大家再熟悉不過了,是用來拷貝記憶體中的內容到目標位址所處的記憶體中。kernel中的函式實現是用彙編來寫的,而其他的拷貝函式也有引用到此實現方式。本篇主要解讀kernel中是如何實現的,**是kernel 5.4版本原始碼。
/*
* copy a buffer from src to dest (alignment handled by the hardware)
* * parameters:
* x0 - dest
* x1 - src
* x2 - n
* returns:
* x0 - dest
*///設定暫存器對應的變數,其中x0、x1、x2分別代表三個引數
dstin .req x0
src .req x1
count .req x2
tmp1 .req x3
tmp1w .req w3
tmp2 .req x4
tmp2w .req w4
dst .req x6
a_l .req x7
a_h .req x8
b_l .req x9
b_h .req x10
c_l .req x11
c_h .req x12
d_l .req x13
d_h .req x14
mov dst, dstin //儲存臨時變數
cmp count, #16
//比較count是否小於16
b.lo .ltiny15 //拷貝長度小於16,不做位址對齊,直接拷貝,跳轉到tiny15
neg tmp2, src //對src取補數後賦值到tmp2
ands tmp2, tmp2, #15
//看tmp2的位址是否時16位元組對其的,只保留後4 bit
b.eq .lsrcaligned //如果位元組對齊跳轉到srcaligned 做對齊拷貝
sub count, count, tmp2 //沒有對其就減去未對其的部分
//對未對其的部分做拷貝,根據對應bit位來確定總位元組數
tbz tmp2, #0,1f
ldrb1 tmp1w, src, #1
//單位元組拷貝
strb1 tmp1w, dst, #11:
tbz tmp2, #1,2f
ldrh1 tmp1w, src, #2
//雙位元組拷貝
strh1 tmp1w, dst, #22:
tbz tmp2, #2,3f
ldr1 tmp1w, src, #4
//4位元組拷貝
str1 tmp1w, dst, #43:
tbz tmp2, #3
,.lsrcaligned
ldr1 tmp1, src, #8
//8位元組拷貝
str1 tmp1, dst, #8
.lsrcaligned:
cmp count, #64
//比較是否大於等於64
b.ge .lcpy_over64 //大於等於64位元組就跳轉到cpy_over64
.ltail63:
//小於則先判斷
ands tmp1, count, #0x30
//判斷是否超過48
b.eq .ltiny15 //超過則對超過48位元組的部分用tiny15來拷貝
cmp tmp1w, #0x20
//與32作比較
b.eq 1f
//超過32位元組就按照48位元組就拷貝3次,等於32就拷貝兩次,小於32就1次
b.lt 2f
ldp1 a_l, a_h, src, #16
stp1 a_l, a_h, dst, #161:
ldp1 a_l, a_h, src, #16
stp1 a_l, a_h, dst, #162:
ldp1 a_l, a_h, src, #16
stp1 a_l, a_h, dst, #16
.ltiny15:
//所有剩餘部分都由tiny15來處理,結束後則退出拷貝,此處也是通過bit位來判斷大小,進行拷貝
tbz count, #3,1f
ldr1 tmp1, src, #8
str1 tmp1, dst, #81:
tbz count, #2,2f
ldr1 tmp1w, src, #4
str1 tmp1w, dst, #42:
tbz count, #1,3f
ldrh1 tmp1w, src, #2
strh1 tmp1w, dst, #23:
tbz count, #0
,.lexitfunc
ldrb1 tmp1w, src, #1
strb1 tmp1w, dst, #1
b .lexitfunc
.lcpy_over64:
subs count, count, #128
//判斷是否大於128位元組
b.ge .lcpy_body_large
//小於128位元組就先拷貝64位元組,剩餘如果還有要拷貝的就用tail63來執行,然後退出。
ldp1 a_l, a_h, src, #16
stp1 a_l, a_h, dst, #16
ldp1 b_l, b_h, src, #16
ldp1 c_l, c_h, src, #16
stp1 b_l, b_h, dst, #16
stp1 c_l, c_h, dst, #16
ldp1 d_l, d_h, src, #16
stp1 d_l, d_h, dst, #16
tst count, #0x3f
b.ne .ltail63
b .lexitfunc
.p2align l1_cache_shift
.lcpy_body_large:
/* pre-get 64 bytes data. */
ldp1 a_l, a_h, src, #16
ldp1 b_l, b_h, src, #16
ldp1 c_l, c_h, src, #16
ldp1 d_l, d_h, src, #161:
stp1 a_l, a_h, dst, #16
ldp1 a_l, a_h, src, #16
stp1 b_l, b_h, dst, #16
ldp1 b_l, b_h, src, #16
stp1 c_l, c_h, dst, #16
ldp1 c_l, c_h, src, #16
stp1 d_l, d_h, dst, #16
ldp1 d_l, d_h, src, #16
subs count, count, #64
b.ge 1b //如果數量滿足條件就64位元組迴圈拷貝
stp1 a_l, a_h, dst, #16
stp1 b_l, b_h, dst, #16
stp1 c_l, c_h, dst, #16
stp1 d_l, d_h, dst, #16
tst count, #0x3f
//測試count是否是0,
b.ne .ltail63 //非0的情況就說明小於64位元組,由tail63來處理
.lexitfunc:
整體的流程分為下面的步驟:
1、小於16位元組的部分使用tiny15處理;
2、小於64位元組大於16位元組用tail63處理;
3、小於128位元組大於64位元組則用cpy_over64處理;
4、大於128位元組的使用cpy_body_large來處理;
5、對於16位元組整倍數的部分直接拷貝16位元組;
該段**通過分段處理來提公升拷貝的效率,不再是乙個位元組乙個位元組的拷貝,對於連續的對其部分,在64位機器上,借助其定址能力進而提公升拷貝的效率。
ARM64架構下面安裝mysql5 7 22
tar xzvf mysql 5.7.27 aarch64.tar.gz c usr local 4.配置mysql mv usr local mysql 5.7.27 aarch64 usr local mysql mkdir p usr local mysql logs chown r mysq...
x86架構和arm構架
x86是英特爾公司開發的並且通治了幾十年.x86反應快在pc應用廣泛.86與arm最大不同在於指令集上.x86跟硬體發揮優勢.但是帶來的功耗大.arm構架指令簡單執行起來快功耗也低.現在智慧型手機和平板很火.平板電腦要求便攜和續航能力.arm構架具有低功耗.使之有了市場.那麼為什麼沒有得到普及原因主...
CPU X86架構和ARM架構入門篇
mips架構 powerpc架構 常見的四大cpu體系結構arm x86 atom mips powerpc,這裡我們來看下主流的x86架構和arm架構。cpu的x86和arm架構有啥區別?指令集又是啥?它誕下amd和intel,孕育了矽谷,讓賈伯斯頂禮膜拜 仙童半導體公司 x86架構 intel ...