超详细:实现 Swift 与 汇编(Asm)代码混编并在真机或模拟器上运行

news2024/11/16 13:32:18

在这里插入图片描述

功能需求

虽然现在  开发的绝对主角是 Swift 语言,不过我们也希望有时 Swift 能够调用小段汇编代码以完成特殊功能。

在本篇博文中,您将学到如下内容:

  • Swift 与 汇编语言混编的基本原理;
  • 如何在模拟器中使用 Swift + x64 汇编指令?
  • 如何在真机中使用 Swift + ARM64 汇编指令?
  • Xcode 如何根据不同编译目标切换不同类型的汇编指令?
  • 实例测试真机上汇编语言执行速度;

关于更多 Swift、C、 intel x64 和 ARM64 汇编语言执行效率比较,请移步如下链接观赏:

  • 有趣的小实验:四种语言搞定“超超超难”剑桥面试数学题
  • 搞定“超超超难”剑桥面试数学题番外篇:ARM64汇编

请系好安全带,本次航行我们将穿越量子微宇宙。

Let‘s go!!!😉

功能分析

1. Swift 与 汇编如何才能成为“好基友”?

大家都知道,在 C 或 C++ 等其它高级语言中我们都可以通过内嵌汇编语言(Inline assembly)的方式来与它方便的“打成一片”。

比如,在以下 C 代码中我们就以内嵌形式调用了汇编代码:

#include <stdio.h>
 
extern int func(void);
// the definition of func is written in assembly language
__asm__(".globl func\n\t"
        ".type func, @function\n\t"
        "func:\n\t"
        ".cfi_startproc\n\t"
        "movl $7, %eax\n\t"
        "ret\n\t"
        ".cfi_endproc");
 
int main(void)
{
    int n = func();
    // gcc's extended inline assembly
    __asm__ ("leal (%0,%0,4),%0"
           : "=r" (n)
           : "0" (n));
    printf("7*5 = %d\n", n);
    fflush(stdout); // flush is intentional
 
    // standard inline assembly in C++
    __asm__ ("movq $60, %rax\n\t" // the exit syscall number on Linux
             "movq $2,  %rdi\n\t" // this program returns 2
             "syscall");
}

不过,可能是  考虑到安全和多平台移植等诸多烦心的事, Swift 语言本身是没有内嵌汇编语言机制的。

所以,为了 Swift 能与汇编 成为“好基友”,我们需要找到 Swift 代码识别并调用汇编的方法:这可以通过桥接 Objective-C(后面简称为:Objc) 代码来实现

2. Objc:缘分一道桥

首先,用 Xcode 创建名为 ‘Asm_X64’ (iOS 类型)的项目,选择 Swift 作为项目主语言。

在 Swift 项目中桥接 Objc 代码很容易,我们只需在 Xcode 中新建一个 Objc 源代码文件,随后 Xcode 会自动为我们创建桥接头文件。

为了简单起见,我们可以直接选择创建 Cocoa Touch Class 类型,这会同时生成 .h 头文件和 .m 文件:

在这里插入图片描述


理论上,我们可以不需要 .m 文件,只需要一个 .h 文件即可,因为本例中 Swift 需要的所有代码都是由汇编而不是 Objc 来实现的。

不过,在项目中只创建一个 .h 文件无法让 Xcode 自动生成桥接头文件(Bridging Header)。

所以,如果大家不嫌手动创建桥接头文件麻烦的话,可以只创建 .h 文件。


我们打算用 Objc 类作为跳板来让 Swift 间接调用汇编代码。So,为我们的 Objc 类起名为 AsmHelper:

在这里插入图片描述


提示:我们后面会介绍 Swift 如何不通过 Objc 类作为跳板来调用汇编代码的方法。


紧接着,Xcode 会自动提示是否创建 Objc 的桥接头文件(Objective-C bridging header),这里当然是选择 创建 了:

在这里插入图片描述

在新创建的 AsmHelper 类中添加一个 calc_max 方法,现在该方法啥也不做只是默默的返回 0:

// AsmHelper.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface AsmHelper : NSObject
-(int)calc_max;
@end

NS_ASSUME_NONNULL_END

// ****************************************************

// AsmHelper.m
#import "AsmHelper.h"

@implementation AsmHelper
- (int)calc_max {
	return 0;
}
@end

还差一步:打开 AsmTest-Bridging-Header.h 桥接头文件,导入 AsmHelper.h。

// AsmTest-Bridging-Header.h 
#import "AsmHelper.h"

准备工作已就绪,下面终于可以进入“正题”了!

3. 如何在模拟器中使用 Swift + x64 汇编指令?

根据我们 Mac 机器中不同的处理器,我们需要分别为 intel 和  Silicon (M1,M2)两种芯片来考虑开发设置。

3.1 intel 芯片的 Mac

如果你使用 intel 芯片的 Mac 来进行开发,那么模拟器实际是在 intel 处理器上运行的。所以我们需要使用 intel x64 类型的汇编指令。

在 Xcode 项目中新建一个 max_x64.s 文件用来存放汇编代码。为了方便 Objc 调用,我们在 max_x64.s 中写了一个函数:

	.text
    .globl      _calc_max_x64_asm
    .p2align    4, 0x90
   	// 方法进入点
_calc_max_x64_asm:
	// 方法构造前缀
    push    %rbp
    mov     %rsp,%rbp
    pushq   %rbx
    pushq   %rdx

	/* 
		实际代码将在此...
	*/

	// 方法析构后缀
	popq    %rdx
    popq    %rbx
    popq    %rbp
    // 返回值放在 rax 寄存器中
    mov     $11,%rax
    ret

需要说明一下:上面 .globl 伪指令的作用是将 _calc_max_x64_asm 作为全局标签来对待,这样我们就可以从外部(Objc中)找到它。

其实从汇编指令层面上来说,是没有所谓“函数或方法”概念的。只要满足以下 5 点要求,任何指令块都可以作为函数或方法来调用:

  1. 确定指令执行的起始地址(方法进入点);
  2. 设置栈;
  3. 处理寄存器的保存和恢复;
  4. 处理传入参数并设置返回值;
  5. 添加返回指令(ret);

以上这些都属于应用程序二进制接口编程(ABI)的范畴,不同语言和系统的实现都有所不同,我们需要按照对应的规范来编写代码。

对于上面的“函数”来说:它没有传入参数,并且有一个 int 类型的返回值。


关于更多汇编语言的知识,感谢兴趣的小伙伴们可以移步到我汇编(Asm)专栏中观赏相关文章:

  • 大熊猫侯佩的 Asm 系列专栏

回到 AsmHelp.h 文件中,我们需要在 Objc 中声明汇编函数的签名:

// AsmHelp.h
extern int calc_max_x64_asm(void);

接着,在 AsmHelp 类的 calc_max 实例方法中调用汇编实现的 calc_max_x64_asm 函数:

@implementation AsmHelper
- (int)calc_max {
    return calc_max_x64_asm();
@end

现在,我们可以回到 Swift 语言中通过 Objc 调用 calc_max_x64_asm 函数了:

import SwiftUI

struct ContentView: View {
    @State var max = 0
    
    var body: some View {
        Text("max is \(max)")
            .font(.title)
            .onAppear {
                max = AsmHelper().calc_max()
            }
    }
}

在模拟器或 Xcode 预览(Preview)中运行上述代码,结果不出所料:

在这里插入图片描述

3.2 Apple Silicon 芯片的 Mac

 Silicon 处理器(M1,M2等)本身就兼容 arm 指令集,所以对于此 Mac 中模拟器汇编语言的适配,可以按照下面 “在 iPhone 真机中” 运行的方案来对待。


小知识:其实在  Silicon 上也可以用 intel x64 “仿真”模式运行模拟器,只需在 Xcode 中设置 Destination Architectures 为 ‘Show Rosetta Destinations’ (或 Show Both)即可:

在这里插入图片描述


4. 如何在真机中使用 Swift + ARM64 汇编指令?

如果在 Xcode 中将构建目标由模拟器变为真机,那么编译上面包含 intel x64 汇编代码的项目 ‘Asm_X64’ 会妥妥的报错:

在这里插入图片描述

这是因为  真机设备的处理器是 arm 架构,要想在真机上运行我们需要使用 ARM64 种类的汇编代码。


  • iPhone 14PM(Pro Max)使用 A16 处理器(4纳米)
  • iPhone XR 使用 A12处理器(7纳米)

在文章最后,我们会分别在以上两种真机上运行 ARM64 汇编测试代码,并比较它们的耗时情况。


现在,为了不与之前 intel x64 汇编代码混淆,我们新建另一个名为 ‘Asm_ARM64’ 的 Xcode 项目,其中 AsmHelper 类的实现和桥接头文件的内容和之前完全相同。

接着,我们创建 max_arm64.s 文件,并填入如下代码:

    .text
    .globl  _calc_max_arm64_asm
    .p2align    2
    // 方法进入点
_calc_max_arm64_asm:
    // 方法构造前缀
    sub     sp,sp,#32
    stp     x29,x30,[sp,#16]
    add     x29,sp,#16

    /* 
        实际代码将在此...
    */
    
    // 方法析构后缀
    ldp     x29,x30,[sp,#16]
    add     sp,sp,#32
    // 返回值放在 x0 寄存器中
    mov     x0,$11
    ret

可以看到:ARM64 实现的函数和 intel x64 汇编类似,都符合各自 ABI 接口的规范。

该项目的 Swift 代码也和 ‘Asm_X86’ 项目中的如出一辙。我们选择真机作为构建目标,编译运行后的结果也应该和之前模拟器上的完全相同。

5. Xcode 如何根据不同编译目标切换不同类型的汇编代码?

细心的小伙伴们可能察觉到了:把 intel x64 和 ARM64 汇编代码分散在两个不同项目中既 不利于测试 又 违反了 DRY 原则。

能不能把它们放在同一个项目中,而根据不同构建目标(真机或模拟器)来切换对应的汇编代码呢?

必须可以!!!

5.1 ”新目标,新征程“

我们回到上面 ‘Asm_X64’ 项目里,在原目标(TARGET)基础之上“克隆”一个新目标:

在这里插入图片描述

修改新目标的名称为 AsmTestARM:

在这里插入图片描述

接着,打开 Scheme 管理界面,同样将新 Scheme 名称也改为 AsmTestARM:

在这里插入图片描述

现在我们有了两个 Scheme:AsmTest 和 AsmTestARM,分别对应于 x86 和 ARM64 汇编代码文件。

关键的部分来了,我们导入之前 ‘Asm_ARM64’ 项目中的 ARM64 汇编文件 max_arm64.s,并将它的 Target 成员关系设为 AsmTestARM:

在这里插入图片描述

同样的,将原来的 x64 汇编文件 max_x64.s 的 Target 成员关系设为 AsmTest:
在这里插入图片描述

5.2 条件编译走起!

上面,我们已经把不同汇编代码文件划分到了对应的 Scheme 中,接下来还需要根据不同构建目标,来选择实际使用的汇编函数。

按如下代码修改 AsmHelper 类中的 calc_max 实例方法:

@implementation AsmHelper
- (int)calc_max {
#if TARGET_IPHONE_SIMULATOR
    return calc_max_x64_asm();
#elif TARGET_OS_IPHONE
    return calc_max_arm64_asm();
#endif
}
@end

如上代码所示,我们使用 #if 宏指令来选择调用合适的汇编函数。同样的,在 AsmHelper.h 中也按相同条件来声明对应的外部函数:

#if TARGET_IPHONE_SIMULATOR
extern int calc_max_x64_asm(void);
#elif TARGET_OS_IPHONE
extern int calc_max_arm64_asm(void);
#endif

原 Swift 代码无需做任何修改。

现在,我们可以根据不同构建目标(模拟器或真机)来切换 Scheme 了:

在这里插入图片描述

至此,项目中不同类型的汇编代码在模拟器或真机上编译运行都不会有任何问题了,棒棒哒!💯

6. 跳过 Objc 直接与汇编代码混编

经过不懈努力,我们完成了 Swift 与汇编语言的混合编译。

不过,实现中使用了 Objc 作为“媒介”,仔细考虑会发现这纯属多余:因为 AsmHelper 类基本自己啥也没干!

Swift 能不能完全甩开 Objc 直接与汇编“在一起”呢?

答案是肯定的!

删除项目中的 AsmHelper.m 文件,并只保留 AsmHelper.h 文件中相关的条件编译代码:

// AsmHelper.h
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

#if TARGET_IPHONE_SIMULATOR
extern int calc_max_x64_asm(void);
#elif TARGET_OS_IPHONE
extern int calc_max_arm64_asm(void);
#endif

/*
@interface AsmHelper : NSObject
-(int)calc_max;
@end
*/

NS_ASSUME_NONNULL_END

回到 Swift 的 ContentView 结构中,创建 calc_max() 方法,其中我们根据目标的架构来直接选择实际的汇编函数。

完整代码如下:

import SwiftUI

struct ContentView: View {
    @State var max = 0
    
    private func calc_max() -> Int {
#if arch(x86_64)
        return Int(calc_max_x64_asm())
#elseif arch(arm64)
        return Int(calc_max_arm64_asm())
#else
        return -1
#endif
    }
     
    var body: some View {
        Text("max is \(max)")
            .font(.title)
            .onAppear {
                max = calc_max()
            }
    }
}

大功告成,Objc 再见!

7. 实例测试真机上汇编语言执行效率;

在 搞定“超超超难”剑桥面试数学题番外篇:ARM64汇编 这篇博文中,我们在 M2 处理器上测试了 ARM64 汇编的表现。

现在,我们用相同的汇编代码在 iPhone 真机上测试一下。

将上面 max_arm64.s 文件的代码改为如下内容:

.equ        total, 63
    .text
    .globl  _calc_max_arm64_asm
    .p2align    2
_calc_max_arm64_asm:
    sub     sp,sp,#32
    stp     x29,x30,[sp,#16]
    add     x29,sp,#16

    mov     w0,1    // a in w0
    mov     w1,w0   // b in w1
    mov     w2,w0   // c in w2
    mov     w3,w0   // d in w3
    mov     w11,wzr // max in w11
start_a_loop:
    cmp     w0,total
    b.hi    end_a_loop
start_b_loop:
    cmp     w1,total
    b.hi    end_b_loop
start_c_loop:
    cmp     w2,total
    b.hi    end_c_loop
start_d_loop:
    cmp     w3,total
    b.hi    end_d_loop
    // 计算 a + b + c + d 的值
    add     w4,w0,w1
    add     w4,w4,w2
    add     w4,w4,w3
    cmp     w4,total
    b.ne    not_equ_63
    // 若等于 a + b + c + d = 63,则计算 ab + bc + cd 的值 x
    mul     w4,w0,w1
    mul     w5,w1,w2
    mul     w6,w2,w3
    add     w5,w5,w6
    add     w4,w4,w5
    // 若 x > max ,则需要更新 max 为 x 值
    cmp     w4,w11
    b.ls    not_equ_63
    mov     w11,w4
not_equ_63:
    add     w3,w3,#1
    b       start_d_loop
end_d_loop:
    mov     w3,wzr
    add     w2,w2,#1
    b 		start_c_loop
end_c_loop:
    mov     w2,wzr
    add     w1,w1,#1
    b       start_b_loop
end_b_loop:
    mov     w1,wzr
    add     w0,w0,#1
    b       start_a_loop
end_a_loop:
    ldp     x29,x30,[sp,#16]
    add     sp,sp,#32
    // 将计算出来的最大值通过 x0 寄存器返回
    mov     x0,x11
    ret
string: .asciz  "max is %ld\n"

将 ContentView 中的 body 也略作更改:

var body: some View {
    Text("max is \(max)")
        .font(.title)
        .onAppear {
            let start = Date.now
            let result = calc_max()
            print("\(String(format: "耗时 %0.5f", start.distance(to: Date.now)))")
            max = result
        }
}

在 iPhone XR 和 iPhone 14 Pro Max 真机运行上面的汇编代码,差距并没有想象那么大:

// 汇编代码执行耗时

// iPhone XR
耗时 0.01920 秒

// iPhone 14PM
耗时 0.01469

为了便于大家横向比较,同样贴出纯 Swift 优化后(Release)代码的执行结果:

// Swift 代码执行耗时

// iPhone XR
耗时 0.02132 秒

// iPhone 14PM
耗时 0.01704

可以发现,在 iPhone 上我们的汇编执行速度要比优化后的 Swift 代码还要快。

此役,在  A系列芯片上汇编终于扳回一局!!! ❤️


同样将 Swift 语言的测试代码贴在下方,以满足小伙伴们的好奇心:

typealias GroupNumbers = (a: Int, b: Int, c: Int, d: Int, rlt: Int)

@inline(__always) fileprivate func value(_ g: GroupNumbers) -> Int {
    g.a * g.b + g.b * g.c + g.c * g.d
}

func calc_max_swift() -> Int {
    var max = 0
    let r = 1...63
    for a in r {
        for b in r {
            for c in r {
                for d in r {
                    if a + b + c + d == 63 {
                        let v = (a: a, b: b, c: c, d: d, rlt: 0)
                        let rlt = value(v)
                        
                        if rlt >= max {
                            max = rlt
                        }
                    }
                }
            }
        }
    }

    return max
}

总结

在本篇博文中,我们图文并茂的详细介绍了如何在真机或模拟器上运行 Swift 和汇编混编后的代码,并通过一个实际例子来测试不同 iPhone 上汇编的执行效率。

最后,还得问一下小伙伴:你们学会了吗?😎

结束语

Hi,我是大熊猫侯佩,一名非自由App开发者,希望我的文章可以解决你的痛点、难点问题。

如果还有问题欢迎在下面一起讨论吧 😉

感谢观赏,再会。

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

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

相关文章

小黑带领阿黄中老黑一起跑步完成了小怪兽,晚上一起吃烤肠西瓜,买了帐篷准备一起露营的leetcode之旅:438. 找到字符串中所有字母异位词

小黑代码 class Solution:def findAnagrams(self, s: str, p: str) -> List[int]:# 串p长度n_p len(p)# 串s长度n_s len(s)# 计数字典flags collections.Counter(p)# 统计字典map_ dict((k, 0) for k in p)# 匹配到的字符个数count 0# 头尾指针left right 0# 目标数…

Python给一个exe执行文件注册持续性的快捷键(热键)的代码实例

本篇文章主要讲解通过python给一个exe文件绑定一个快捷键、并取消快捷键(热键)的实操方法。 日期:2023年6月11日 作者:任聪聪 实现按下快捷键即可启动软件的效果说明 启动软件注册热键呼出其他软件或本体的效果说明: 演示材料说明:在download文件目录下存放一个可执行的…

数据结构与算法之美 | 栈

栈结构&#xff1a;后进者先出&#xff0c;先进者后出 栈是一种“操作受限”的线性表 当某个数据集合只涉及在一端插入和删除数据&#xff0c;并且满足后进先出、先进后出的特性&#xff0c;这时我们就应该首选“栈”这种数据结构 栈的实现 使用数组实现&#xff1a;顺序栈…

【数据结构】二叉树(一)

目录 一、树的概念及结构 1、树的概念 2、树的相关概念 3、树的表示 二、二叉树概念及结构 1、二叉树的概念 2、特殊二叉树 3、二叉树的性质 4、二叉树的存储结构 4.1 顺序存储结构 4.2 链式存储结构 三、二叉树顺序结构及实现 1、二叉树的顺序结构 2、堆的概念及结构 3、堆…

OMG--RTPS(Real Time Publish Subscribe Protocol)

OMG--RTPS&#xff08;Real Time Publish Subscribe Protocol&#xff09; 1 概述2 内容缩写DDS 有线协议的要求RTPS 有线协议The RTPS Platform Independent Model (PIM)The Structure ModuleThe Messages ModuleThe Behavior ModuleThe Discovery Module The RTPS Platform S…

Xuperchain多节点网络搭建+加节点+测试

环境准备 创建网络部署环境 # 在xuperchain目录执行 make testnet 种子节点 # 查看node1节点连接地址netURL cd node1 ./bin/xchain-cli netURL preview # 得到如下结果,实际使用时,需要将ip配置节点的真实ip,port配置成 /ip4/{{ip}}/tcp/{{port}}/p2p/Qmf2HeHe4sspGkfR…

深度学习应用篇-计算机视觉-OCR光学字符识别[7]:OCR综述、常用CRNN识别方法、DBNet、CTPN检测方法等、评估指标、应用场景

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

上课补充的知识

题目 char类型的默认值是\u0000 数组的创建方式 数组的遍历 遍历:从头到尾,依次访问数组每一个位置,获取每一个位置的元素.形式如下: 我们通过数组的下标操作数组,所以for循环变量操作的也是数组下标 开始:开始下标0 结束:结束下标length-1 如何变化: 语法&#xff1a; for…

大学结束啦!!!

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

神舟笔记本“性能、娱乐、省电、安静”模式之间的区别

前言&#xff1a;主要是对比神舟笔记本电脑“性能、娱乐、省电、安静”模式之间的区别 工具及硬件 名称版本号电脑Z8D6 2.5k屏鲁大师6.1023.xxx 之所以使用鲁大师&#xff0c;主要是为了节省时间.另外仅仅只是为了做横向对比&#xff0c;不需要太专业的工具。 实验中有两个变…

六级备考6天|CET-6|听力第一二三四讲|复习回顾|长对话篇章|14:00~16:30

长对话 篇章 目录 听写笔记 练习讲义 听写笔记 1. 听力策略 听前&#xff1a;读题——分析文章——预测题目 听中&#xff1a;划出听到的内容——对应程度高为正确选项 听后&#xff1a;不听题目——往下读题 2. 重点词汇 proofread / ˈpruːfriːd / …

CodeWhisperer插件使用体验

官方教程点击跳转 使用工具 1.vscode 2.插件(AWS Toolkit),免费使用 安装以后如何使用 1.首先要有一个aws账号 2.插件下载好以后登录aws账号&#xff0c;我们主要用这款插件的CodeWhisperer这个功能&#xff0c;其它的自行看官方教程了解。 注意事项&#xff1a;我们在从vs…

杭州互联网医疗Java实习一面

目录 1.java集合知道哪些2.ArrayList和LinkedList插入效率对比3.HashMap的底层结构4.HashMap怎么实现线程安全4.介绍下reentrantlock5.Redis分布式锁的实现原理7.知道哪些排序算法8.快排的原理9.Spring的AOP作用和原理10.MySQL的InnoDB索引结构11.网络中TCP和UDP的区别12.JVM的…

delphi 调用youtube-dl命令,下载youtube视频,原理及源代码

一、概要 1、Youtube-dl工具 强大的视频下载命令行工具Youtube-dl项目由Ricardo Garcia创建于2008年&#xff0c;源代码由Python编写&#xff0c;托管在GitHub上&#xff0c; 最初仅支持YouTube&#xff0c;但随着项目的发展&#xff0c;也开始支持其他视频网站&#xff0c;优势…

如何优化selenium webdriver的执行速度

目录 前言 在page_source中断言text比直接使用text属性断言要快 元素越具体&#xff0c;获取text的速度越快 使用变量去缓存没有变化的元素 快速在文本框中输入大文本 使用动态等待进行动态/AJAX 操作而不是固定睡眠 最后 前言 让自动化测试脚本正常工作只是自动化测试的…

微信小程序的自动化测试框架Minium详解,10分钟掌握

目录 前言 minium 是为小程序专门开发的自动化框架 文档使用 框架依赖运行环境部署 使用 打开工具 特别说明&#xff1a; 总结&#xff1a; 前言 微信发布了小程序的自动化测试框架Minium&#xff0c;提供了多种运行验证方式&#xff0c;其特点&#xff1a; 支持一套脚…

Alloy Tutorial(2)LastPass; cacheMemory

文章目录 LastPass整体 solution 代码&#xff1a; cacheMemory LastPass module LastPass/** LastPass password map** A simple example to explain basics of Alloy. ** The PassBook keeps track of a set of users passwords for a set of URLs. * For each User/URL pai…

【阿里云】第一次进行域名注册、备案以及使用全过程

前言 随着ChatGPT的爆火&#xff0c;让我直面感受到了一项技术的突破可以产生堪比原子弹爆炸的威力&#xff0c;因而在品尝过ChatGPT带来的便利与甜头后&#xff0c;就一直在跟进&#xff0c;同时也在能力范围内&#xff0c;让数十位朋友使用上了ChatGPT 前段时间&#xff0c…

ftrace学习 —— user_events的用法

参考 https://docs.kernel.org/trace/user_events.html 测试程序 samples/user_events/example.c tools/testing/selftests/user_events/ftrace_test.c 正文 通过user_event可以实现对应用程序的跟踪&#xff0c;类似linux内核中的tracepoint那样。相似的方法还有借助/sys…

走进docker

一、Docker 概述 1、Docker的概念 • Docker是一个开源的应用容器引擎&#xff0c;基于go语言开发并遵循了apache2.0协议开源 • Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的“虚拟机” • Docker 的容器技术可以在一台主机上轻松为任何应用创建一…