ARM体系结构学习笔记:过程调用标准AAPC、 ARM32调用约定、ARM64调用约定

news2024/11/15 4:43:03

20211205185052

参数传递的本质: 将上层函数变量复制一份, 传给下层函数.

过程调用标准AAPC(Arm Architecture Procedure Call)

20220118084646
有了标准, 才能够进行C调用汇编或者汇编调用C

ARM32调用约定

20220118084824

参数是不同位数传参情况, 额外的参数被caller进行入栈, callee进行出栈

寄存器传参

20220118085114

寄存器返回

20220118085234

汇编调用C程序/C调用汇编程序

20220118085619

32位实现64位加法运算

20220118085751

Arm的栈结构

20220118085916

堆栈传参数与栈平衡

20220118090516

子程序需要保存的寄存器

20220118091115

20220118091308

子程序返回PUSH {LR}/ POP {PC}

20220118091739

结构体传参

void my_argIsStruct(TPoint3D a1, int a2, int a3) {    
    //结构体作为参数,会把其字段按顺序依次放入寄存器或者栈,相当于把结构体拆解为多个参数,按照ARM传递参数规则来传递
    a1.dx_0 = 0;
    a1.dy_4 = 4;
    a1.dz_8 = 8;
    printf("结构体参数,其字段1:%d", a1.dx_0);
    printf("结构体参数,其字段2:%d", a1.dy_4);
    printf("结构体参数,其字段3:%d", a1.dz_8);
    printf("结构体参数之后的第2个int参数:%d", a2);
    printf("结构体参数之后的第3个int参数:%d", a3);
}
结构体作为参数,会把其字段按顺序依次放入寄存器或者栈,相当于把结构体拆解为多个参数,按照ARM传递参数规则来传递
hello32:0286B5BA STR             R2, [SP,#0x18+var_C]    ; varc = r2
hello32:0286B5BC STR             R1, [SP,#0x18+var_10]   ; var10 = r1
hello32:0286B5BE STR             R0, [SP,#0x18+var_14]   ; var14 = r0
hello32:0286B5C0 STR             R3, [SP,#0x18+var_18]   ; var18 = r3
hello32:0286B5C2 MOVS            R0, #0
hello32:0286B5C4 STR             R0, [SP,#0x18+var_14]   ; var14 = 0
hello32:0286B5C6 MOVS            R0, #4
hello32:0286B5C8 STR             R0, [SP,#0x18+var_10]   ; var10 = 4
hello32:0286B5CA MOVS            R0, #8
hello32:0286B5CC STR             R0, [SP,#0x18+var_C]    ; varc = 8
R0-3会作为参数进行传递, 其他参数会压栈处理, 并且R7会赋值为SP,后面基于R7(SP)进行寻址操作
hello32:0286B5B0 my_argIsStruct
hello32:0286B5B0
hello32:0286B5B0 var_18= -0x18
hello32:0286B5B0 var_14= -0x14
hello32:0286B5B0 var_10= -0x10
hello32:0286B5B0 var_C= -0xC
hello32:0286B5B0
hello32:0286B5B0 PUSH            {R7,LR}                 ; save r7, lr. r7 will as sp
hello32:0286B5B2 MOV             R7, SP                  ; r7 = sp
hello32:0286B5B4 SUB             SP, SP, #0x10           ; local var
hello32:0286B5B6 LDR.W           R12, [R7,#8]            ; ????????????????????????????????????
hello32:0286B5BA STR             R2, [SP,#0x18+var_C]    ; varc = r2
hello32:0286B5BC STR             R1, [SP,#0x18+var_10]   ; var10 = r1
hello32:0286B5BE STR             R0, [SP,#0x18+var_14]   ; var14 = r0
hello32:0286B5C0 STR             R3, [SP,#0x18+var_18]   ; var18 = r3
hello32:0286B5C2 MOVS            R0, #0
hello32:0286B5C4 STR             R0, [SP,#0x18+var_14]   ; var14 = 0
hello32:0286B5C6 MOVS            R0, #4
hello32:0286B5C8 STR             R0, [SP,#0x18+var_10]   ; var10 = 4
hello32:0286B5CA MOVS            R0, #8
hello32:0286B5CC STR             R0, [SP,#0x18+var_C]    ; varc = 8
hello32:0286B5CE LDR             R1, [SP,#0x18+var_14]   ; r1 is arg1 0
hello32:0286B5D0 LDR             R0, =(unk_286B485 - 0x286B5D6)
hello32:0286B5D2 ADD             R0, PC                  ; unk_286B485 ; r0 is arg0 is str
hello32:0286B5D4 BLX             unk_286B6D0             ; printf(r0, r1)
hello32:0286B5D8 LDR             R1, [SP,#0x18+var_10]
hello32:0286B5DA LDR             R0, =(unk_286B463 - 0x286B5E0)
hello32:0286B5DC ADD             R0, PC                  ; unk_286B463
hello32:0286B5DE BLX             unk_286B6D0
hello32:0286B5E2 LDR             R1, [SP,#0x18+var_C]
hello32:0286B5E4 LDR             R0, =(unk_286B3E5 - 0x286B5EA)
hello32:0286B5E6 ADD             R0, PC                  ; unk_286B3E5
hello32:0286B5E8 BLX             unk_286B6D0
hello32:0286B5EC LDR             R1, [SP,#0x18+var_18]   ; var18 = r3
hello32:0286B5EE LDR             R0, =(unk_286B435 - 0x286B5F4)
hello32:0286B5F0 ADD             R0, PC                  ; unk_286B435
hello32:0286B5F2 BLX             unk_286B6D0             ; printf(r0, r3)
hello32:0286B5F6 LDR             R1, [R7,#8]             ; stack var [r7+8]
hello32:0286B5F8 LDR             R0, =(unk_286B407 - 0x286B5FE)
hello32:0286B5FA ADD             R0, PC                  ; unk_286B407
hello32:0286B5FC BLX             unk_286B6D0             ; printf(r0, stack var[r7+8])
hello32:0286B600 ADD             SP, SP, #0x10
hello32:0286B602 POP             {R7,PC}
hello32:0286B602 ; End of function my_argIsStruct

相关重点

Q: 为什么会将SP赋值给R7 ?

A: R7会赋值为SP,后面基于R7(SP)进行寻址操作, 所以为什么local var都是负数偏移

Q: LDR.W R12, [R7,#8] 又有什么意义?

A: 目前并不清楚, 和友人一起确认就是废物代码

ARM64调用约定

参数1~参数8 分别保存到 X0~X7 寄存器中 ,剩下的参数从右往左依次入栈,被调用者实现栈平衡,返回值存放在 X0 中。

https://docs.microsoft.com/zh-cn/cpp/build/arm64-windows-abi-conventions?view=msvc-170

AArch64状态下的Canary机制

int test9(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int stack1) {
    return a1 + a2 + a3 + a4 + a5 + a7 + a8 + stack1;
}

// ## arm learn 01
int main(int argc, char const *argv[]) {
    while (1) {
        //arm 64 args
        test9(1, 2, 3, 4, 5, 6, 7, 8, 9);
        sleep(5);
    }
    return 0;
}
hello:0000005C45037910 SUB             SP, SP, #0x30
hello:0000005C45037914 LDR             W8, [SP,#0x30+arg_0]    ; stack_var1 to r8
hello:0000005C45037918 STR             W0, [SP,#0x30+var_4]    ; r0 to var4
hello:0000005C4503791C STR             W1, [SP,#0x30+var_8]    ; r1 to var8
hello:0000005C45037920 STR             W2, [SP,#0x30+var_C]    ; r2 to varc
hello:0000005C45037924 STR             W3, [SP,#0x30+var_10]   ; r3 to var16
hello:0000005C45037928 STR             W4, [SP,#0x30+var_14]   ; r4 to var20
hello:0000005C4503792C STR             W5, [SP,#0x30+var_18]   ; r5 to var24
hello:0000005C45037930 STR             W6, [SP,#0x30+var_1C]   ; r6 to var28
hello:0000005C45037934 STR             W7, [SP,#0x30+var_20]   ; r7 to var32
hello:0000005C45037938 STR             W8, [SP,#0x30+var_24]   ; r8 = stack_var1 to var36
hello:0000005C4503793C LDR             W8, [SP,#0x30+var_4]    ; r8 = 1
hello:0000005C45037940 LDR             W9, [SP,#0x30+var_8]    ; r9 = 2
hello:0000005C45037944 ADD             W8, W8, W9
hello:0000005C45037948 LDR             W9, [SP,#0x30+var_C]
hello:0000005C4503794C ADD             W8, W8, W9
hello:0000005C45037950 LDR             W9, [SP,#0x30+var_10]
hello:0000005C45037954 ADD             W8, W8, W9
hello:0000005C45037958 LDR             W9, [SP,#0x30+var_14]
hello:0000005C4503795C ADD             W8, W8, W9
hello:0000005C45037960 LDR             W9, [SP,#0x30+var_1C]
hello:0000005C45037964 ADD             W8, W8, W9
hello:0000005C45037968 LDR             W9, [SP,#0x30+var_20]
hello:0000005C4503796C ADD             W8, W8, W9
hello:0000005C45037970 LDR             W9, [SP,#0x30+var_24]
hello:0000005C45037974 ADD             W0, W8, W9              ; ret var use w0
hello:0000005C45037978 ADD             SP, SP, #0x30
hello:0000005C4503797C RET

20211202220612

20211202221224

20211202222442

我们通过堆栈数据的展示可以了解到堆栈是8字节对齐模式存储的

20211202223118

void my_argIsStruct(TPoint3D a1, int a2, int a3) {    
    //结构体作为参数,会把其字段按顺序依次放入寄存器或者栈,相当于把结构体拆解为多个参数,按照ARM传递参数规则来传递
    a1.dx_0 = 0xb1;
    a1.dy_4 = 0xb2;
    a1.dz_8 = 0xb3;
    printf("filed1:%d\n", a1.dx_0);
    printf("filed2:%d\n", a1.dy_4);
    printf("filed2:%d\n", a1.dz_8);
    printf("a2:%d\n", a2);
    printf("a3:%d\n", a3);
}

int main() {
    ...
    TPoint3D a1={0xa1, 0xa2, 0xa3};
    my_argIsStruct(a1, 0xa4, 0xa5);
    ...
}
hello:00000056BBEAF810 ; =============== S U B R O U T I N E =======================================
hello:00000056BBEAF810
hello:00000056BBEAF810 ; Attributes: bp-based frame
hello:00000056BBEAF810
hello:00000056BBEAF810 my_argIsStruct
hello:00000056BBEAF810
hello:00000056BBEAF810 var_60= -0x60
hello:00000056BBEAF810 var_58= -0x58
hello:00000056BBEAF810 var_50= -0x50
hello:00000056BBEAF810 var_48= -0x48
hello:00000056BBEAF810 var_3C= -0x3C
hello:00000056BBEAF810 var_38= -0x38
hello:00000056BBEAF810 var_34= -0x34
hello:00000056BBEAF810 var_30= -0x30
hello:00000056BBEAF810 var_2C= -0x2C
hello:00000056BBEAF810 var_28= -0x28
hello:00000056BBEAF810 var_24= -0x24
hello:00000056BBEAF810 var_20= -0x20
hello:00000056BBEAF810 var_18= -0x18
hello:00000056BBEAF810 var_C= -0xC
hello:00000056BBEAF810 var_8= -8
hello:00000056BBEAF810 var_4= -4
hello:00000056BBEAF810 var_s0=  0
hello:00000056BBEAF810
hello:00000056BBEAF810 SUB             SP, SP, #0x70
hello:00000056BBEAF814 STP             X29, X30, [SP,#0x60+var_s0]                      ;save fp, lr
hello:00000056BBEAF818 ADD             X29, SP, #0x60                                   ;这句
hello:00000056BBEAF81C MOV             X8, #0xC                                         ;sizeof(TPoint3D)
hello:00000056BBEAF820 MOV             W9, #0xB1                                        ;to reg9
hello:00000056BBEAF824 MOV             W10, #0xB2                                       ;to reg10
hello:00000056BBEAF828 MOV             W11, #0xB3                                       ;to reg11
hello:00000056BBEAF82C ADRP            X12, #aFiled1D@PAGE     ; "filed1:%d\n"          ;to reg12 with pc rel
hello:00000056BBEAF830 ADD             X12, X12, #aFiled1D@PAGEOFF ; "filed1:%d\n"       
hello:00000056BBEAF834 ADRP            X13, #aFiled2D@PAGE     ; "filed2:%d\n"          ;to reg13 with pc rel
hello:00000056BBEAF838 ADD             X13, X13, #aFiled2D@PAGEOFF ; "filed2:%d\n"
hello:00000056BBEAF83C ADRP            X14, #aA2D@PAGE         ; "a2:%d\n"              ;to reg14 with pc rel
hello:00000056BBEAF840 ADD             X14, X14, #aA2D@PAGEOFF ; "a2:%d\n"
hello:00000056BBEAF844 ADRP            X15, #aA3D@PAGE         ; "a3:%d\n"              ;to reg15 with pc rel
hello:00000056BBEAF848 ADD             X15, X15, #aA3D@PAGEOFF ; "a3:%d\n"              
hello:00000056BBEAF84C SUB             X16, X29, #-var_C                                ;
hello:00000056BBEAF850 SUB             X17, X29, #-var_20
hello:00000056BBEAF854 STUR            X0, [X29,#var_20]                                ;                          stack_var_20 = x0 = 0XA10XA2
hello:00000056BBEAF858 STUR            X1, [X29,#var_18]                                ;                          stack_var_18 = x1 = 0XA3
hello:00000056BBEAF85C MOV             X0, X16                                          ;                          x0 = stack_var_C
hello:00000056BBEAF860 MOV             X1, X17                                          ;                          x1 = stack_var_20
hello:00000056BBEAF864 STUR            W2, [X29,#var_2C]                                ;                          stack_var_2c = w2 = 0XA4
hello:00000056BBEAF868 MOV             X2, X8                                           ;                          x2 = x8 = 12 = sizeof(TPoint3D) 
hello:00000056BBEAF86C STR             W3, [SP,#0x60+var_30]                            ;[r->s] w3 -> var30
hello:00000056BBEAF870 STR             W9, [SP,#0x60+var_34]                            ;[r->s] w9 -> var34
hello:00000056BBEAF874 STR             W10, [SP,#0x60+var_38]                           ;[r->s] w10-> var38
hello:00000056BBEAF878 STR             W11, [SP,#0x60+var_3C]                           ;[r->s] w11-> var3c
hello:00000056BBEAF87C STR             X12, [SP,#0x60+var_48]                           ;[r->s] w12-> var48
hello:00000056BBEAF880 STR             X13, [SP,#0x60+var_50]                           ;[r->s] w13-> var50
hello:00000056BBEAF884 STR             X14, [SP,#0x60+var_58]                           ;[r->s] w14-> var58
hello:00000056BBEAF888 STR             X15, [SP,#0x60+var_60]                           ;[r->s] w15-> var60
hello:00000056BBEAF88C BL              loc_56BBEAF6A0                                   ;                           memcpy
hello:00000056BBEAF890 LDUR            W9, [X29,#var_2C]
hello:00000056BBEAF894 STUR            W9, [X29,#var_24]
hello:00000056BBEAF898 LDR             W10, [SP,#0x60+var_30]
hello:00000056BBEAF89C STUR            W10, [X29,#var_28]
hello:00000056BBEAF8A0 LDR             W11, [SP,#0x60+var_34]
hello:00000056BBEAF8A4 STUR            W11, [X29,#var_C]
hello:00000056BBEAF8A8 LDR             W3, [SP,#0x60+var_38]
hello:00000056BBEAF8AC STUR            W3, [X29,#var_8]
hello:00000056BBEAF8B0 LDR             W4, [SP,#0x60+var_3C]
hello:00000056BBEAF8B4 STUR            W4, [X29,#var_4]
hello:00000056BBEAF8B8 LDUR            W1, [X29,#var_C]
hello:00000056BBEAF8BC LDR             X0, [SP,#0x60+var_48]
hello:00000056BBEAF8C0 BL              loc_56BBEAF680
hello:00000056BBEAF8C4 LDUR            W1, [X29,#var_8]
hello:00000056BBEAF8C8 LDR             X8, [SP,#0x60+var_50]
hello:00000056BBEAF8CC MOV             X0, X8
hello:00000056BBEAF8D0 BL              loc_56BBEAF680
hello:00000056BBEAF8D4 LDUR            W1, [X29,#var_4]
hello:00000056BBEAF8D8 LDR             X8, [SP,#0x60+var_50]
hello:00000056BBEAF8DC MOV             X0, X8
hello:00000056BBEAF8E0 BL              loc_56BBEAF680
hello:00000056BBEAF8E4 LDUR            W1, [X29,#var_24]
hello:00000056BBEAF8E8 LDR             X8, [SP,#0x60+var_58]
hello:00000056BBEAF8EC MOV             X0, X8
hello:00000056BBEAF8F0 BL              loc_56BBEAF680
hello:00000056BBEAF8F4 LDUR            W1, [X29,#var_28]
hello:00000056BBEAF8F8 LDR             X8, [SP,#0x60+var_60]
hello:00000056BBEAF8FC MOV             X0, X8
hello:00000056BBEAF900 BL              loc_56BBEAF680
hello:00000056BBEAF904 LDP             X29, X30, [SP,#0x60+var_s0]
hello:00000056BBEAF908 ADD             SP, SP, #0x70
hello:00000056BBEAF90C RET
hello:00000056BBEAF90C ; End of function my_argIsStruct

通过上面的汇编代码我们知道,loc_56BBEAF6A0是memcpy, 但是为什么会产生memcpy呢?

20211205134956

我最开始一直没搞明白,如果编译器只是把寄存器存储到栈,那么挨个赋值不就完事儿了么?类似于下面的2句,也就完成了结构体到堆栈的传输

hello:00000056BBEAF854 STUR            X0, [X29,#var_20]                                ;                          stack_var_20 = x0 = 0XA10XA2
hello:00000056BBEAF858 STUR            X1, [X29,#var_18]                                ;                          stack_var_18 = x1 = 0XA3

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/908365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

交叉编译相关知识

1、目标板与主机之间的连接: 目标板和主机之间通常可以使用串口、以太网接口、USB接口以及JTAG接口等连接方式。 (1)、串行通信: 串行通信接口常用的有9针串口( DB9 )和25针串口(DB25),通信距…

IDEA创建Mybatis格式XML文件

设置位置:File | Settings | Editor | File and Code Templates 选择Files,点击号 Name中输入xml模板名(名称自行决定),后缀名extension输入xml(固定) 内容处输入Mybatis的xml文件模板内容&…

数据结构 - 线性表的定义和基本操作

一、定义 线性表是具有相同特性的数据元素的一个有限序列。 线性表: 由n(n≥0)个数据元素(结点)组成的有限序列。线性表中数据元素是一对一的关系,每个结点最多有一个直接前驱,和一个直接后继 二、线性表的基本操作 …

【AI绘画--七夕篇】:七夕特别教程,使用SDXL绘制你的心上人(Stable Diffusion)(封神榜—妲己)

目录 前言0、介绍0-0、结果展示0-1、Stable Diffusion0-2、sdxl介绍 一、云端部署Stable Diffusion1-1、云端平台的优势 二、平台介绍三、注册账号并且开始炼制3-1、购买算力并创建工作空间3-2、启动工作空间3-3、应用市场一键安装3-4、使用Stable-Diffusion作图 四、有女朋友的…

cuda gdb调试

如果cudaDeviceEnablePeerAccess函数不支持或不起作用,您仍然可以尝试其他方法来实现GPU之间的数据交换和通信。以下是一些替代方法: 通过主机内存进行数据传输: 如果GPU之间的数据交换不是非常频繁,您可以将数据从一个GPU复制到…

【c语言】五子棋(EasyX图形库+背景音乐)

大家好,有没有觉得写了好多c语言代码,面对的都是黑框框控制台,当我们学习了基础的c语言知识,和EasyX图形库后,终于可以和黑框框saygoodbye,今天要分享给大家的是小游戏五子棋,跟着小张一起学习吧 EasyX图形…

(四)Doceke安装MySQL镜像+Docker启动MySQL容器

Doceke安装MySQL镜像/Docker启动MySQL容器 一、doceke安装MySQL镜像 切换到root用户,su root 。 1、启动Docker 启动:sudo systemctl start docker 停止:systemctl stop docker 重启:systemctl restart docker 查看docker运行…

视频汇聚平台EasyCVR安防视频监控在地下停车场中的具体应用方案

一、背景 随着我国城市化进程的加快,汽车已成为人们生活中不可缺少的交通工具,但在许多城市中,买车容易,停车难的问题愈发突出。特别是在人群密集的商场、写字楼和地下停车场,车流量大、车况复杂。传统的人工判断方式耗…

go、java、.net、C#、nodejs、vue、react、python程序问题进群咨询

1、面试辅导 2、程序辅导 3、一对一腾讯会议辅导 3、业务逻辑辅导 4、各种bug帮你解决。 5、培训小白 6、顺利拿到offer

【网络基础实战之路】基于三层架构实现一个企业内网搭建的实战详解

系列文章传送门: 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 【网络基础实战之路】基于…

Lombok生成的Getter和Setter的名称对于“eMail”或“xAxis”等属性存在大小写转换异常

问题 最新开发中,遇到一个字段映射问题。我们先看问题案例: 明明代码中第二个字母是大写,结果测试接口时发现变成了小写字母。 分析 通过网上查询发现,这属于Lombok的bug。而且早在2015年就有人在GitHub上提出了issues。 Names o…

基于SpringBoot房产销售系统【附ppt|开题|万字文档(LW)和搭建文档】

主要功能 前台界面: ①首页、房源信息推荐、房源信息展示、查看更多等 ②房源信息、房源名称、房源户型、销售姓名等 ③购房、预约、点我收藏、评论等 ④个人中心、我的收藏、支付等 后台登录: ①首页、个人中心:修改密码、用户信息管理等 ②…

三角函数与圆,角度和弧度 (草稿,建设中)

目录 1 三角函数与圆,角度和弧度 1.1 三角形 1.2 圆形 2 角度 3 弧度 rad 4 角度,弧度的换算 2 三角函数 1 三角函数与圆,角度和弧度 1.1 三角形 角度弧长sin()cos()tan() 1.2 圆形 半径,周长,弧长半径面积 …

Linux面试笔试题(2)

27、按下( A ) 键能终止当前运行的命令 A. Ctrl-C B. Ctrl-F C. Ctrl-B D. Ctrl-D 28、下面哪个命令用来启动X Window ( C ) A. runx B. Startx C. startX D. xwin 29、用 “rm -i”,系统会提示什么来让你确认( B ) A.命令行的每个选项 B.是否真的删除 C.是否有写的权限 D…

计算机网络第2章(物理层)

计算机网络第2章(物理层) 2.1 物理层的基本概念2.2 物理层下面的传输媒体2.2.1 导引型传输媒体2.2.2 非导引型传输媒体 2.3 传输方式2.3.1 串行传输和并行传输2.3.2 同步传输和异步传输2.3.3 单向通信(单工)、双向交替通信&#x…

【Leetcode】105.从前序与中序遍历序列构造二叉树

一、题目 1、题目描述 给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。 示例1: 输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] 输出: [3,9,20,null,null,15,7]示例…

口腔牙科门诊挂号系统 微信小程序的设计与实现_1171u-

随着信息时代的来临,过去的“口腔助手”管理方式缺点逐渐暴露,现在对过去的“口腔助手”管理方式的缺点进行分析,采取计算机方式构建“口腔助手”小程序。本文通过阅读相关文献,研究国内外相关技术,提出了一种预约信息…

睿趣科技:抖音小店新人最适合卖什么产品

随着移动互联网的不断发展,短视频平台如今已经成为了人们日常生活中不可或缺的一部分。其中,抖音作为国内短视频平台的代表,不仅让用户可以欣赏到各种有趣、创意的短视频内容,同时也为创业者提供了一个广阔的创业机会——抖音小店…

【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典)

【数据结构入门指南】二叉树顺序结构: 堆及实现(全程配图,非常经典) 一、前言:二叉树的顺序结构二、堆的概念及结构三、堆的实现(本篇博客以实现小堆为例)3.1 准备工作3.2 初始化3.3 堆的插入3.3.1 向上调…

【五子棋】

五子棋 文章目录 五子棋前言一、登录功能二.哈希表管理用户的会话和房间三.基于Websocket连接开发的功能1.匹配功能2.游戏房间3.挑战功能4.人机对战5.聊天功能 前言 这篇博客主要详细介绍我的五子棋项目的核心功能的实现细节,也就是详细介绍五子棋各个功能是如何实…