ARM64架構下memcpy實現原理

2021-10-22 18:51:33 字數 3970 閱讀 3416

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 ...