swift4-汇编分析枚举内存布局

一、枚举的内存原理

1.1 常规case

Swift 复制代码
enum TestEnum {
case test1, test2, test3 }
var t = TestEnum.test1
t = .test2
t = .test3

枚举是常规的case的情况-是采取一个字节来存枚举变量


通过拿到枚举的内存地址,看地址里面存的枚举值情况窥探枚举内存存储情况
var t = TestEnum.test1 //内存存的是0 0x00000001000106e0 00 00 00 00 00 00 00 00
print(Mems.ptr(ofVal: &t))
t = .test2 //内存存的是1 0x00000001000106e0 01 00 00 00 00 00 00 00
t = .test3 //2 内存存的是2 0x00000001000106e0 02 00 00 00 00 00 00 00

print(MemoryLayout<TestEnum>.size) //1
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.alignment) //1

1.2 原始值case的情况

Swift 复制代码
var t = TestEnum.test1 //0x00000001000106c8  00 00 00 00 00 00 00 00
print(Mems.ptr(ofVal: &t))
t = .test2 //0x00000001000106c8  01 00 00 00 00 00 00 00
t = .test3 // 0x00000001000106c8  02 00 00 00 00 00 00 00

print(MemoryLayout<TestEnum>.size) //1
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.alignment) //1


结论原始值不影响枚举成员值的存储情况,和前面常规case还是一样的,原始值不占用枚举变量的内存

1.3 关联值的情况

Swift 复制代码
enum TestEnum {
case test1(Int, Int, Int)
case test2(Int, Int)
case test3(Int)
case test4(Bool)
case test5
}
var e = TestEnum.test1(1, 2, 3)
e = .test2(4, 5)
e = .test3(6)
e = .test4(true)
e = .test5


现象
    enum TestEnum {
        case test1(Int, Int, Int)
        case test2(Int, Int)
        case test3(Int)
        case test4(Bool)
        case test5
    }
    
    // 1个字节存储成员值
    // N个字节存储关联值(N取占用内存最大的关联值),任何一个case的关联值都共用这N个字节
    // 共用体
    
    // 小端:高高低低
    // 01 00 00 00 00 00 00 00
    // 02 00 00 00 00 00 00 00
    // 03 00 00 00 00 00 00 00
    // 00 枚举成员值
    // 00 00 00 00 00 00 00
    var e = TestEnum.test1(1, 2, 3)
    print(Mems.ptr(ofVal: &e))
    
    // 04 00 00 00 00 00 00 00
    // 05 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 01 枚举成员值
    // 00 00 00 00 00 00 00
    e = .test2(4, 5)
    print(Mems.memStr(ofVal: &e))
    
    // 06 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 02 枚举成员值
    // 00 00 00 00 00 00 00
    e = .test3(6)
    
    // 01 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 03 枚举成员值
    // 00 00 00 00 00 00 00
    e = .test4(true)
    
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 00 00 00 00 00 00 00 00
    // 04
    // 00 00 00 00 00 00 00
    e = .test5
    print(MemoryLayout<TestEnum>.size) //25
    print(MemoryLayout<TestEnum>.stride) //32
    print(MemoryLayout<TestEnum>.alignment) //8



结论:
 // 1个字节存储成员值
 // N个字节存储关联值(N取占用内存最大的关联值),任何一个case的关联值都共用这N个字节
    

1.4 只有一个case的情况

Swift 复制代码
enum TestEnum {
   case test1
}


print(MemoryLayout<TestEnum>.size) //0
print(MemoryLayout<TestEnum>.stride) //1
print(MemoryLayout<TestEnum>.alignment) //1

1.5 一个case的关联值

Swift 复制代码
enum TestEnum {
case test(Int)
}
var t = TestEnum.test(10)

print(MemoryLayout<TestEnum>.size) //8
print(MemoryLayout<TestEnum>.stride) //8
print(MemoryLayout<TestEnum>.alignment) //8

因为只有一个case 只需要花8个字节来存你的关联值就行

综上 存储成员值的情况前提是有多个case,如果只有一个case的情况就没必要再花一个字节的内存去存成员值

二、switch底层原理

大概原理 取出那个成员值,然后拿成员值和case里面的值进行比较,和case 里面的哪个值相同就跳转到相应的位置

三、汇编

3.1 程序的本质

3.2 寄存器与内存 的关系

var a = 3

var b = a + 1 这句代码要经过如下操作

为什么不直接在内存中移动,cpu 他支持的指令他是有限制的

第一个限定 他是不支持数据内存挪内存的,如果你想把一个内存的数据挪动到宁一个内存,必须要经过寄存器,这是规定;

第二个 如果你想进行一些运算,必须将数据拉到cpu里面,运算完再送回去

3.3 编程语言的发展

3.4 汇编语言的种类

3.5 常见汇编指令

(这里面装的是内存地址)%rbp寄存器里面存的内存地址值- 0x18

movq -0x18(%rbp), %rax

movq根据这个内存地址对应的存贮空间的数据取出来赋值%rax

leaq -0x18(%rbp), %rax

leaq根据这个内存地址赋值%rax

获取地址和对应地址的内存数据

Swift 复制代码
//
//  MemsTest.swift
//  TestSwift
//
//  Created by lxj on 2025/3/2.
//  Copyright © 2025 lxj
//


import Foundation

public enum MemAlign : Int {
    case one = 1, two = 2, four = 4, eight = 8
}

private let _EMPTY_PTR = UnsafeRawPointer(bitPattern: 0x1)!

/// 辅助查看内存的小工具类
public struct Mems<T> {
    private static func _memStr(_ ptr: UnsafeRawPointer,
                                _ size: Int,
                                _ aligment: Int) ->String {
        if ptr == _EMPTY_PTR { return "" }
        
        var rawPtr = ptr
        var string = ""
        let fmt = "0x%0\(aligment << 1)lx"
        let count = size / aligment
        for i in 0..<count {
            if i > 0 {
                string.append(" ")
                rawPtr += aligment
            }
            let value: CVarArg
            switch aligment {
            case MemAlign.eight.rawValue:
                value = rawPtr.load(as: UInt64.self)
            case MemAlign.four.rawValue:
                value = rawPtr.load(as: UInt32.self)
            case MemAlign.two.rawValue:
                value = rawPtr.load(as: UInt16.self)
            default:
                value = rawPtr.load(as: UInt8.self)
            }
            string.append(String(format: fmt, value))
        }
        return string
    }
    
    private static func _memBytes(_ ptr: UnsafeRawPointer,
                                  _ size: Int) -> [UInt8] {
        var arr: [UInt8] = []
        if ptr == _EMPTY_PTR { return arr }
        for i in 0..<size {
            arr.append((ptr + i).load(as: UInt8.self))
        }
        return arr
    }
    
    /// 获得变量的内存数据(字节数组格式)
    public static func memBytes(ofVal v: inout T) -> [UInt8] {
        return _memBytes(ptr(ofVal: &v), MemoryLayout.stride(ofValue: v))
    }
    
    /// 获得引用所指向的内存数据(字节数组格式)
    public static func memBytes(ofRef v: T) -> [UInt8] {
        let p = ptr(ofRef: v)
        return _memBytes(p, malloc_size(p))
    }
    
    /// 获得变量的内存数据(字符串格式)
    ///
    /// - Parameter alignment: 决定了多少个字节为一组
    public static func memStr(ofVal v: inout T, alignment: MemAlign? = nil) -> String {
        let p = ptr(ofVal: &v)
        return _memStr(p, MemoryLayout.stride(ofValue: v),
                       alignment != nil ? alignment!.rawValue : MemoryLayout.alignment(ofValue: v))
    }
    
    /// 获得引用所指向的内存数据(字符串格式)
    ///
    /// - Parameter alignment: 决定了多少个字节为一组
    public static func memStr(ofRef v: T, alignment: MemAlign? = nil) -> String {
        let p = ptr(ofRef: v)
        return _memStr(p, malloc_size(p),
                       alignment != nil ? alignment!.rawValue : MemoryLayout.alignment(ofValue: v))
    }
    
    /// 获得变量的内存地址
    public static func ptr(ofVal v: inout T) -> UnsafeRawPointer {
        return MemoryLayout.size(ofValue: v) == 0 ? _EMPTY_PTR : withUnsafePointer(to: &v) {
            UnsafeRawPointer($0)
        }
    }
    
    /// 获得引用所指向内存的地址
    public static func ptr(ofRef v: T) -> UnsafeRawPointer {
        if v is Array<Any>
            || Swift.type(of: v) is AnyClass
            || v is AnyClass {
            return UnsafeRawPointer(bitPattern: unsafeBitCast(v, to: UInt.self))!
        } else if v is String {
            var mstr = v as! String
            if mstr.memType() != .heap {
                return _EMPTY_PTR
            }
            return UnsafeRawPointer(bitPattern: unsafeBitCast(v, to: (UInt, UInt).self).1)!
        } else {
            return _EMPTY_PTR
        }
    }
    
    /// 获得变量所占用的内存大小
    public static func size(ofVal v: inout T) -> Int {
        return MemoryLayout.size(ofValue: v) > 0 ? MemoryLayout.stride(ofValue: v) : 0
    }
    
    /// 获得引用所指向内存的大小
    public static func size(ofRef v: T) -> Int {
        return malloc_size(ptr(ofRef: v))
    }
}

public enum StringMemType : UInt8 {
    /// TEXT段(常量区)
    case text = 0xd0
    /// taggerPointer
    case tagPtr = 0xe0
    /// 堆空间
    case heap = 0xf0
    /// 未知
    case unknow = 0xff
}

extension String {
    mutating public func memType() -> StringMemType {
        let ptr = Mems.ptr(ofVal: &self)
        return StringMemType(rawValue: (ptr + 15).load(as: UInt8.self) & 0xf0)
            ?? StringMemType(rawValue: (ptr + 7).load(as: UInt8.self) & 0xf0)
            ?? .unknow
    }
}
相关推荐
染指111010 小时前
21.第二阶段x64游戏实战-分析采集物偏移
汇编·游戏·反游戏外挂·游戏逆向·x64dbg·x64游戏
楠木s3 天前
常见汇编代码及其指定
java·汇编·数据库·安全·网络攻击模型·二进制·栈溢出
suyong_yq6 天前
调试Cortex-M85 MCU启动汇编和链接命令文件 - 解题一则
汇编·arm开发·嵌入式系统
染指111010 天前
18.第二阶段x64游戏实战-MFC列表框
汇编·c++·windows·游戏·游戏逆向·x64dbg
RaLi和夕13 天前
单片机学习笔记9.数码管
汇编·笔记·单片机·嵌入式硬件·学习
yu41062113 天前
GCC 内建函数汇编展开详解
汇编
手打猪大屁17 天前
ARM裸机开发——I.MX6U_汇编LED灯驱动
汇编·arm开发
zhmc18 天前
Keil A51汇编伪指令
汇编
攻城狮7号18 天前
【第48节】探究汇编使用特性:从基础到混合编程
汇编·c++·windows
打工人你好24 天前
Visual Studio Code 在.S汇编文件中添加调试断点及功能简介
汇编·ide·vscode