ARM64函数调用流程分析

ARM64函数调用流程分析

  • 1 ARM64 函数调用实例
  • 2 对应代码的分析
    • 2.1 main函数及其对应的汇编程序
      • 2.1.1 main的C代码实现
      • 2.1.2 main函数对应汇编及其分析
      • 2.1.3 执行完成之后栈的存放情况
    • 2.2 test_fun_a函数及其对应的汇编程序
      • 2.2.1 test_fun_a函数的C实现
      • 2.2.2 test_fun_a函数对应汇编及其分析
      • 2.2.3 执行完成之后栈帧的使用情况
    • 2.3 test_fun_b函数及其对应的汇编程序
      • 2.3.1 test_func_b函数的C实现
      • 2.3.2 test_fun_b函数对应汇编及其分析
      • 2.3.3 执行完成之后栈帧的使用情况

ARM64 程序调用标准

1 ARM64 函数调用实例

下图是介绍一个简单函数调用的示例,在该示例中简单介绍了栈的使用。
在这里插入图片描述

2 对应代码的分析

2.1 main函数及其对应的汇编程序

2.1.1 main的C代码实现

int main(void)
{long a = 1;                                                                             long b = 2;printf("The current function is %s a:%ld b:%ld\r\n", __func__, a, b); test_fun_a(a, b, 0, 1); a = a + b;b = a + b;return 0;
}

2.1.2 main函数对应汇编及其分析

  • 0000000000000114 <main>:main函数的入口
  • 114: a9be7bfd stp x29, x30, [sp, #-32]! 将sp = sp - 32,为main函数开一个32Byte的栈空间,然后将x29(FP),X30(LR)寄存器的值存放在SP和SP + 8的位置处。
  • 118: 910003fd mov x29, sp 将SP寄存器的值存放到X29(FP)寄存器中,即FP寄存器指向当前main函数的栈顶。
  • 11c: d2800020 mov x0, #0x1 // #1 将局部变量a的值保存到x0寄存器中
  • 120: f9000be0 str x0, [sp, #16] 将局部变量a的值保存到sp + 16的位置处。
  • 124: d2800040 mov x0, #0x2 // #2 将局部变量b的值保存到x0寄存器中
  • 128: f9000fe0 str x0, [sp, #24] 将局部变量b的值保存到sp + 24栈内存处
  • 12c: f9400fe3 ldr x3, [sp, #24] 从栈中加载局部变量b的值到x3寄存器中
  • 130: f9400be2 ldr x2, [sp, #16]从栈中加载局部变量a的值到x2寄存器中
  • 134: 90000000 adrp x0, 0 <test_fun_b>加载test_func_b函数的地址到x0寄存器中
  • 138: 91000001 add x1, x0, #0x0将x0 + 0的值保存到x1寄存器中
  • 13c: 90000000 adrp x0, 0 <test_fun_b>加载test_func_b函数的地址到x0寄存器中
  • 140: 91000000 add x0, x0, #0x0将x0 + 0的值保存到x0寄存器中
  • 144: 94000000 bl 0 <printf>调用函数printf
  • 148: d2800023 mov x3, #0x1 // #1将1保存到x3寄存器中,作为调用test_fun_a函数的第4个参数
  • 14c: d2800002 mov x2, #0x0 // #0将0保存到寄存器x2中,作为调用test_fun_a函数的第3个参数
  • 150: f9400fe1 ldr x1, [sp, #24]从栈中取出局部变量b的值,放到x1寄存器中,作为调用test_fun_a的第2个参数
  • 154: f9400be0 ldr x0, [sp, #16]从栈中取出局部变量a的值,放到x0寄存器中,作为调用test_fun_a的第1个参数
  • 158: 94000000 bl 80 <test_fun_a>调用test_func_a函数,其参数分别为前面的x0 ~ x3寄存器的值
  • 15c: f9400be1 ldr x1, [sp, #16] 加载局部变量a的值到x1寄存器
  • 160: f9400fe0 ldr x0, [sp, #24]加载局部变量b的值到x0寄存器
  • 164: 8b000020 add x0, x1, x0 a = a + b
  • 168: f9000be0 str x0, [sp, #16] 将计算到的局部变量a的值重新存到栈中
  • 16c: f9400fe1 ldr x1, [sp, #24]从栈中取出局部变量b的值
  • 170: f9400be0 ldr x0, [sp, #16]从栈中取出局部变量a的值
  • 174: 8b000020 add x0, x1, x0 b = a + b
  • 178: f9000fe0 str x0, [sp, #24]将新计算得到的局部变量b的值重新保存到栈中
  • 17c: 52800000 mov w0, #0x0 // #0给w0寄存器赋值为0,该操作是用在ret指令执行时,返回0值。
  • 180: a8c27bfd ldp x29, x30, [sp], #32恢复x29(FP)和X30(LR)的值,同时SP = SP + 32
  • 184: d65f03c0 ret 返回调用的指令,该指令执行的时候会返回lr寄存器指向的函数中。
                                                                                             
0000000000000114 <main>:114:   a9be7bfd        stp     x29, x30, [sp, #-32]!118:   910003fd        mov     x29, sp11c:   d2800020        mov     x0, #0x1                        // #1120:   f9000be0        str     x0, [sp, #16]124:   d2800040        mov     x0, #0x2                        // #2128:   f9000fe0        str     x0, [sp, #24]12c:   f9400fe3        ldr     x3, [sp, #24]130:   f9400be2        ldr     x2, [sp, #16]134:   90000000        adrp    x0, 0 <test_fun_b>138:   91000001        add     x1, x0, #0x013c:   90000000        adrp    x0, 0 <test_fun_b>140:   91000000        add     x0, x0, #0x0144:   94000000        bl      0 <printf>148:   d2800023        mov     x3, #0x1                        // #114c:   d2800002        mov     x2, #0x0                        // #0150:   f9400fe1        ldr     x1, [sp, #24]154:   f9400be0        ldr     x0, [sp, #16]158:   94000000        bl      80 <test_fun_a>15c:   f9400be1        ldr     x1, [sp, #16]160:   f9400fe0        ldr     x0, [sp, #24]164:   8b000020        add     x0, x1, x0168:   f9000be0        str     x0, [sp, #16]16c:   f9400fe1        ldr     x1, [sp, #24]170:   f9400be0        ldr     x0, [sp, #16]174:   8b000020        add     x0, x1, x0178:   f9000fe0        str     x0, [sp, #24]17c:   52800000        mov     w0, #0x0                        // #0180:   a8c27bfd        ldp     x29, x30, [sp], #32184:   d65f03c0        ret

2.1.3 执行完成之后栈的存放情况

在这里插入图片描述

2.2 test_fun_a函数及其对应的汇编程序

2.2.1 test_fun_a函数的C实现

void test_fun_a(long m, long n, long x, long y)
{long b = 2;long c = 3;printf("The current function is %s b:%ld c:%ld\r\n", __func__, b, c); test_fun_b(b, c, 0, 2); b = b + c + m;c = b + c + n;
}

2.2.2 test_fun_a函数对应汇编及其分析

  • 0000000000000080 <test_fun_a>:test_fun_a函数的入口
  • 80: a9bc7bfd stp x29, x30, [sp, #-64]!为test_fun_a函数开栈64B,同时把X29(FP),X30(LR)保存到栈顶sp和sp + 8的栈内存位置处
  • 84: 910003fd mov x29, sp将sp保存到x29(FP)寄存器中,相当于FP指向栈的栈顶
  • 88: f90017e0 str x0, [sp, #40]将参数1保存到栈的sp + 40栈内存位置处
  • 8c: f90013e1 str x1, [sp, #32]将参数2保存到栈sp + 32的栈内存位置处
  • 90: f9000fe2 str x2, [sp, #24]将参数3保存到栈sp + 24栈内存位置处
  • 94: f9000be3 str x3, [sp, #16]将参数4保存到栈sp + 16栈内存位置处
  • 98: d2800040 mov x0, #0x2 // #2将test_fun_a函数的局部变量b保存到x0寄存器中
  • 9c: f9001be0 str x0, [sp, #48]将test_fun_a函数的局部变量b保存到sp + 48栈内存位置处
  • a0: d2800060 mov x0, #0x3 // #3将test_fun_a函数的局部变量c保存到x1寄存器中
  • a4: f9001fe0 str x0, [sp, #56]将test_fun_a函数的局部变量c保存到栈sp + 56栈内存位置处
  • a8: f9401fe3 ldr x3, [sp, #56]从栈中取出局部变量c的值放到x3寄存器中
  • ac: f9401be2 ldr x2, [sp, #48]从栈中取出局部变量b的值放到x2寄存器中
  • b0: 90000000 adrp x0, 0 <test_fun_b>将test_fun_b函数的地址加载到x0寄存器中
  • b4: 91000001 add x1, x0, #0x0 x1 = x0 + 0,其中x0保存的是test_fun_b的起始地址
  • b8: 90000000 adrp x0, 0 <test_fun_b>将test_fun_b函数的地址加载到x0寄存器中
  • bc: 91000000 add x0, x0, #0x0 x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址
  • c0: 94000000 bl 0 <printf>调用函数printf
  • c4: d2800043 mov x3, #0x2 // #2给x3寄存器赋值为2,作为test_fun_b的第4个参数
  • c8: d2800002 mov x2, #0x0 // #0给x2寄存器赋值为0,作为test_func_b的第三个参数
  • cc: f9401fe1 ldr x1, [sp, #56]从栈中取出局部变量c,存放到x1寄存器,作为test_fun_b的第二个参数
  • d0: f9401be0 ldr x0, [sp, #48]从栈中取出局部变量b,存放到x0寄存器,作为test_fun_b的第一个参数
  • d4: 94000000 bl 0 <test_fun_b>调用test_fun_b函数,x0 ~ x3作为test_fun_a的四个参数
  • d8: f9401be1 ldr x1, [sp, #48]从栈中取出test_fun_a的局部变量b,放到x1寄存器中
  • dc: f9401fe0 ldr x0, [sp, #56]从栈中取出test_fun_a的局部变量c,放到x0寄存器中
  • e0: 8b000020 add x0, x1, x0 c = b + c,将c的结果保存到x0寄存器中。
  • e4: f94017e1 ldr x1, [sp, #40]从栈中取出调用test_fun_a时传入的第1个参数取出,放到x1寄存器中
  • e8: 8b000020 add x0, x1, x0 c = c + m,将计算的结果放到x0寄存器中
  • ec: f9001be0 str x0, [sp, #48]将计算的结果x0的值重新保存到局部变量b的栈内存位置处
  • f0: f9401be1 ldr x1, [sp, #48]从栈中取出局部变量b的值放到x1寄存器中。
  • f4: f9401fe0 ldr x0, [sp, #56]从栈中取出局部变量x的值放到x0寄存器中
  • f8: 8b000020 add x0, x1, x0c = b + c
  • fc: f94013e1 ldr x1, [sp, #32]从栈中取出调用test_fun_a函数时传入的第2个参数放到x1寄存器中
  • 100: 8b000020 add x0, x1, x0 c = c + n,计算的结果放到x0寄存器中
  • 104: f9001fe0 str x0, [sp, #56]将计算的新值存放到原局部变量c的栈内存位置处
  • 108: d503201f nop空操作
  • 10c: a8c47bfd ldp x29, x30, [sp], #64恢复X29(FP),X30(LR)寄存器的值,同时sp = sp + 64栈指针寄存器
  • 110: d65f03c0 ret返回X30(LR)寄存器保存的返回函数处
0000000000000080 <test_fun_a>:80:   a9bc7bfd        stp     x29, x30, [sp, #-64]!84:   910003fd        mov     x29, sp 88:   f90017e0        str     x0, [sp, #40]8c:   f90013e1        str     x1, [sp, #32]90:   f9000fe2        str     x2, [sp, #24]94:   f9000be3        str     x3, [sp, #16]98:   d2800040        mov     x0, #0x2                        // #2   9c:   f9001be0        str     x0, [sp, #48]a0:   d2800060        mov     x0, #0x3                        // #3   a4:   f9001fe0        str     x0, [sp, #56]a8:   f9401fe3        ldr     x3, [sp, #56]ac:   f9401be2        ldr     x2, [sp, #48]b0:   90000000        adrp    x0, 0 <test_fun_b>b4:   91000001        add     x1, x0, #0x0b8:   90000000        adrp    x0, 0 <test_fun_b>bc:   91000000        add     x0, x0, #0x0c0:   94000000        bl      0 <printf>c4:   d2800043        mov     x3, #0x2                        // #2c8:   d2800002        mov     x2, #0x0                        // #0cc:   f9401fe1        ldr     x1, [sp, #56]d0:   f9401be0        ldr     x0, [sp, #48]                                                 d4:   94000000        bl      0 <test_fun_b>d8:   f9401be1        ldr     x1, [sp, #48]dc:   f9401fe0        ldr     x0, [sp, #56]e0:   8b000020        add     x0, x1, x0e4:   f94017e1        ldr     x1, [sp, #40]e8:   8b000020        add     x0, x1, x0ec:   f9001be0        str     x0, [sp, #48]f0:   f9401be1        ldr     x1, [sp, #48]f4:   f9401fe0        ldr     x0, [sp, #56]f8:   8b000020        add     x0, x1, x0fc:   f94013e1        ldr     x1, [sp, #32]100:   8b000020        add     x0, x1, x0104:   f9001fe0        str     x0, [sp, #56]108:   d503201f        nop10c:   a8c47bfd        ldp     x29, x30, [sp], #64110:   d65f03c0        ret

2.2.3 执行完成之后栈帧的使用情况

在这里插入图片描述

2.3 test_fun_b函数及其对应的汇编程序

2.3.1 test_func_b函数的C实现

void test_fun_b(long m, long n, long x, long y)
{long c = 3;long d = 4;printf("The current function is %s c:%ld d:%ld\r\n", __func__, c, d); c = c + d + m;d = c + d + n;
}

2.3.2 test_fun_b函数对应汇编及其分析

  • 0000000000000000 <test_fun_b>:test_fun_b函数的入口
  • 0: a9bc7bfd stp x29, x30, [sp, #-64]!为test_fun_b函数开栈64B,同时把X29(FP),X30(LR)保存到栈顶sp和sp + 8的栈内存位置处
  • 4: 910003fd mov x29, sp将sp保存到x29(FP)寄存器中,相当于FP指向栈的栈顶
  • 8: f90017e0 str x0, [sp, #40]将参数1保存到栈的sp + 40栈内存位置处
  • c: f90013e1 str x1, [sp, #32]将参数2保存到栈sp + 32的栈内存位置处
  • 10: f9000fe2 str x2, [sp, #24]将参数3保存到栈sp + 24栈内存位置处
  • 14: f9000be3 str x3, [sp, #16]将参数4保存到栈sp + 16栈内存位置处
  • 18: d2800060 mov x0, #0x3 // #3将test_fun_b函数的局部变量c保存到x0寄存器中
  • 1c: f9001be0 str x0, [sp, #48]将test_fun_b函数的局部变量c保存到sp + 48栈内存位置处
  • 20: d2800080 mov x0, #0x4 // #4将test_fun_b函数的局部变量d保存到x1寄存器中
  • 24: f9001fe0 str x0, [sp, #56]将test_fun_b函数的局部变量d保存到栈sp + 56栈内存位置处
  • 28: f9401fe3 ldr x3, [sp, #56]从栈中取出局部变量d的值放到x3寄存器中
  • 2c: f9401be2 ldr x2, [sp, #48]从栈中取出局部变量c的值放到x2寄存器中
  • 30: 90000000 adrp x0, 0 <test_fun_b>将test_fun_b函数的地址加载到x0寄存器中
  • 34: 91000001 add x1, x0, #0x0x1 = x0 + 0,其中x0保存的是test_fun_b的起始地址
  • 38: 90000000 adrp x0, 0 <test_fun_b>将test_fun_b函数的地址加载到x0寄存器中
  • 3c: 91000000 add x0, x0, #0x0x0 = x0 + 0,其中x0保存的是test_fun_b的起始地址
  • 40: 94000000 bl 0 <printf>调用函数printf
  • 44: f9401be1 ldr x1, [sp, #48]从栈中取出局部变量c,存放到x1寄存器
  • 48: f9401fe0 ldr x0, [sp, #56]从栈中取出局部变量d,存放到x0寄存器
  • 4c: 8b000020 add x0, x1, x0 d = c + d,将d的结果保存到x0寄存器中。
  • 50: f94017e1 ldr x1, [sp, #40]从栈中取出调用test_fun_b时传入的第1个参数取出,放到x1寄存器中
  • 54: 8b000020 add x0, x1, x0 d = d + m
  • 58: f9001be0 str x0, [sp, #48]将计算的结果x0的值重新保存到局部变量c的栈内存位置处
  • 5c: f9401be1 ldr x1, [sp, #48]从栈中取出局部变量c的值放到x1寄存器中。
  • 60: f9401fe0 ldr x0, [sp, #56]从栈中取出局部变量d的值放到x0寄存器中
  • 64: 8b000020 add x0, x1, x0 c = c + d
  • 68: f94013e1 ldr x1, [sp, #32]从栈中取出调用test_fun_b函数时传入的第2个参数放到x1寄存器中
  • 6c: 8b000020 add x0, x1, x0 c = c + n
  • 70: f9001fe0 str x0, [sp, #56]将计算的新值存放到原局部变量d的栈内存位置处
  • 74: d503201f nop空操作
  • 78: a8c47bfd ldp x29, x30, [sp], #64恢复X29(FP),X30(LR)寄存器的值,同时sp = sp + 64栈指针寄存器
  • 7c: d65f03c0 ret返回X30(LR)寄存器保存的返回函数处
0000000000000000 <test_fun_b>:0:   a9bc7bfd        stp     x29, x30, [sp, #-64]!4:   910003fd        mov     x29, sp8:   f90017e0        str     x0, [sp, #40]c:   f90013e1        str     x1, [sp, #32]10:   f9000fe2        str     x2, [sp, #24]14:   f9000be3        str     x3, [sp, #16]18:   d2800060        mov     x0, #0x3                        // #31c:   f9001be0        str     x0, [sp, #48]20:   d2800080        mov     x0, #0x4                        // #424:   f9001fe0        str     x0, [sp, #56]28:   f9401fe3        ldr     x3, [sp, #56]2c:   f9401be2        ldr     x2, [sp, #48]30:   90000000        adrp    x0, 0 <test_fun_b>                                            34:   91000001        add     x1, x0, #0x038:   90000000        adrp    x0, 0 <test_fun_b>3c:   91000000        add     x0, x0, #0x040:   94000000        bl      0 <printf>44:   f9401be1        ldr     x1, [sp, #48]48:   f9401fe0        ldr     x0, [sp, #56]4c:   8b000020        add     x0, x1, x050:   f94017e1        ldr     x1, [sp, #40]54:   8b000020        add     x0, x1, x058:   f9001be0        str     x0, [sp, #48]5c:   f9401be1        ldr     x1, [sp, #48]60:   f9401fe0        ldr     x0, [sp, #56]64:   8b000020        add     x0, x1, x068:   f94013e1        ldr     x1, [sp, #32]6c:   8b000020        add     x0, x1, x070:   f9001fe0        str     x0, [sp, #56]74:   d503201f        nop     78:   a8c47bfd        ldp     x29, x30, [sp], #647c:   d65f03c0        ret

2.3.3 执行完成之后栈帧的使用情况

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

帆软报表系统未授权重置授权

子曰&#xff1a;“父在观其志&#xff0c;父没观其行。三年无改于父之道&#xff0c;可谓孝矣。” 未授权重置授权 构造payload&#xff0c;访问漏洞url&#xff1a; /ReportServer?opfr_server&cmdsc_version_info&showtoolbarfalse漏洞证明&#xff1a; 文笔生…

信创测试的应用是什么

信创测试作为评估创意和创新项目的工具&#xff0c;为企业的发展提供了重要的支持和指导。它能够帮助企业降低风险、优化资源配置&#xff0c;促进创意与创新的迭代和改进。其具体应用&#xff0c;小编带大家一起来看看详情吧! 一、产品和服务创新 信创测试可以用于评估新产品和…

opencv 文档识别+UI界面识别系统

目录 一、实现和完整UI视频效果展示 主界面&#xff1a; 识别结果界面&#xff1a; 查看处理图片过程&#xff1a; 查看历史记录界面&#xff1a; 二、原理介绍&#xff1a; 将图像变换大小->灰度化->高斯滤波->边缘检测 轮廓提取 筛选第三步中的轮廓&#xf…

Seaborn数据可视化(四)

目录 1.绘制箱线图 2.绘制小提琴图 3.绘制多面板图 4.绘制等高线图 5.绘制热力图 1.绘制箱线图 import seaborn as sns import matplotlib.pyplot as plt # 加载示例数据&#xff08;例如&#xff0c;使用seaborn自带的数据集&#xff09; tips sns.load_dataset("t…

架构评估-架构师之路(十二)

软件系统质量属性 软件系统质量熟悉分为 开发期质量属性 和 运行期质量属性。 质量属性 性能&#xff1a;指 系统的响应能力&#xff0c;如 响应时间&#xff0c;吞吐率。 设计策略&#xff1a;优先级队列、增加计算资源、减少计算开销、引入并发机制、采用资源调度。 可靠…

【数据仓库】Linux、CentOS源码安装Superset

Linux、CentOS源码安装Superset步骤&#xff0c;遇到的各种问题。 报错问题&#xff1a; Linux下pip版本问题 You are using pip version 8.1.2, however version 22.2.2 is available. 解决办法&#xff1a; 安装python3的pip yum install python3-pip再升级 pip3 install…

Linux —— keepalived

简介 Keepalived 是一个用 C 语言编写的路由软件。这个项目的主要目标是为 Linux 系统和基于 Linux 的基础设施提供简单而强大的负载均衡和高可用性功能。 Keepalived 开源并且免费的软件。 Keepalived 的2大核心功能 1. loadbalance 负载均衡 LB&#xff1a;ipvs--》lvs软件…

node.js 简单使用 开始

1.概要 问&#xff1a;体验一下node.js 看一下如何运行。 答&#xff1a;使用命令 node 文件名.js 2.举例 2.1 代码准备(main.js) console.log(第一行node.js代码); 2.2 运行效果

网络安全入口设计模式

网络安全入口涵盖了几种设计模式&#xff0c;包括全局路由模式、全局卸载模式和健康终端监控模式。网络安全入口侧重于&#xff1a;全局路由、低延迟故障切换和在边缘处减轻攻击。 上图包含了3个需求。 •网络安全入口模式封装了全局路由模式。因此&#xff0c;实现可以将请求路…

springBoot防止重复提交

两种方法&#xff0c; 一种是后端实现&#xff0c;较复杂&#xff0c;要通过自定义注解和AOP以及Redis组合实现 另一种是前端实现&#xff0c;简单&#xff0c;只需通过js&#xff0c;设置过期时间&#xff0c;一定时间内&#xff0c;多次点击按钮只生效一次 后端实现 自定义注…

cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容。应以 ‘{layoutlib}‘ 等等开头

不与世俗为伍。哪怕这是自己许给自己的诅咒。 —— 宫崎骏 《红猪》 最近&#xff0c;在使用最新版的AndroidStudio打开一个两年前的项目时候&#xff0c;报了一个如下的错误&#xff1a;【cvc-complex-type.2.4.a: 发现了以元素 ‘base-extension‘ 开头的无效内容】。应以 ‘…

从2023年世界机器人大会发现机器人新趋势

机器人零部件为何成2023年世界机器人大会关注热门&#xff1f; 在原先&#xff0c;机器人的三大核心零部件是控制系统中的控制器、驱动系统中的伺服电机和机械系统中的精密减速器。如今&#xff0c;机器人的主体框架结构已经落实&#xff0c;更多机器人已经开始深入到各类场景中…

论文阅读 FOCUS-AND-DETECT: A SMALL OBJECT DETECTION FRAMEWORK FOR AERIAL IMAGES

文章目录 FOCUS-AND-DETECT: A SMALL OBJECT DETECTION FRAMEWORK FOR AERIAL IMAGESABSTRACT1 Introduction2 Related Work3 Focus-and-Detect3.1 Overview3.2 Focus Stage3.2.1 Generating Ground-Truth Boxes of Focal Regions Using Gaussian Mixture Model 3.3 Detection …

横扫“盲区”、“看透”缺陷,维视智造推出短波红外相机

在可见光领域&#xff0c;工业相机的视觉应用已经十分成熟&#xff0c;但在日常的客户咨询中&#xff0c;我们也经常接到一些“超纲需求”——客户想要检测“白底上的白色缺陷”、“不透明包装内的透明物体有无”等&#xff0c;均属于可见光无法实现的检测&#xff0c;而市面上…

Ubuntu20.04安装软件报错:The following packages have unmet dependencies

Ubuntu20.04更换阿里云源后安装软件都会报错&#xff1a;The following packages have unmet dependencies 查看资料&#xff0c;大概是ubuntu本身的源比较版本较老&#xff0c;而阿里云的源比较新&#xff0c;因此版本不匹配造成依赖的库不匹配&#xff0c;所以只要将阿里云的…

基于 SVG 的图形交互方案实践

不知道从什么时候起&#xff0c;人们开始喜欢上数字大屏这种“花里胡哨”的东西&#xff0c;仿佛只要用上“科技蓝”这样神奇的色调&#xff0c;就可以让一家公司焕然一新&#xff0c;瞬间变得科技感满满。不管数字大屏的实际意义&#xff0c;是用来帮助企业监控和决策&#xf…

汽车制造业外发文件时 如何阻断泄密风险?

汽车制造业是我国国民经济发展的支柱产业之一&#xff0c;具有产业链长、关联度高、就业面广、消费拉动大等特性。汽车制造行业景气度与宏观经济、居民收入水平和固定资产投资密切相关。 汽车制造业产业链长&#xff0c;关联度高&#xff0c;汽车制造上游行业主要为钢铁、化工…

Docker搭建elasticsearch+kibana测试

最近需要做大数据画像&#xff0c;所以先简单搭建一个eskibana学习使用&#xff0c;记录一下搭建过程和遇到的问题以及解决办法 1.拉取es和kibana镜像 在拉取镜像之前先搜索一下 elasticsearch发现是存在elasticsearch镜像的&#xff0c;我一般习惯性拉取最新镜像&#xff0c…

CSS中的vertical-align属性

vertical-align 1.CSS属性 - vertical-align 2.深入理解vertical-align – line boxes This property affects the vertical positioning inside a line box of the boxes generated by an inline-levelelement. 官方文档的翻译&#xff1a;vertical-align会影响 行内块级元素…

如何将下载的安装包导入PyCharm

1. 下载安装包 这里以pyke为例。下载好之后解压缩&#xff0c;然后放入/Lib/site-packages/pyke-1.1.1 2. 打开PyCharm的终端进行安装 python setup.py install 3. 安装好之后导入即可使用 import pyke