zoukankan      html  css  js  c++  java
  • 看雪-课程-汇编快速入门

    看雪-课程-汇编快速入门

    July 14, 2020 6:46 PM

    参考 看雪-汇编快速入门

    资料

    1.参考资料
    《汇编语言(第3版)》王爽著 等
    2.课程资源
    看雪论坛:http://bbs.pediy.com/
    链接: https://pan.baidu.com/s/17Yuz0YgpHJd6k1YEuwavBg 提取码: xkt7

    基础知识

    机器指令能被计算机直接识别。
    汇编指令需要通过编译器转为机器指令。
    汇编指令和机器指令的差别在于指令的表示方法上。汇编指令是机器指令便于记忆的书写格式。
    在不同的设备中,不同的机器语言指令集。

    进制:一种逢N进一的运算,最小值0,最大值N

    • 二进制B
    • 十进制D
    • 十六进制H
    • 八进制O

    转换方法:
    十进制转二进制:除2取余
    二进制转十进制:加权
    二进制转十六进制:4位一组

    计算机:
    输入设备 输出设备 存储器 运算器 控制器

    • 存储器:用于存储数据并在需要时提供
      外部存储器 硬盘 光盘
      内部存储器 RAM ROM
    • CPU
      运算器:对数据进行各种算术运算和逻辑运算,即对数据进行加工处理
      控制器:完成协调和指挥整个计算机系统的操作

    存储单位
    计算机中最小的信息单位bit(比特),二进制单位
    计算机中存储数据的最小单位是Byte(B字节)
    1TB=1024GB=10242014MB=102410241024KB=1024102410241024B
    存储单元
    存储器被划分成了若干个存储单元,一个存储单元可以存储一个字节(8个二进制位),每个存储单元从0开始顺序编号。
    对于一个有128个存储单元的存储器:容量位128字节,编号0-127.
    每个单元有两部分构成:一般用十六进制表示。
    存储单元的地址
    存储单元的内容

    CPU对存储器的读写通过三种总线控制:地址总线、数据中心、控制总线

    • 地址总线 的宽度决定了CPU的寻址能力
    • 数据总线 的宽度决定了CPU与其他期间进行数据传送时的一次数据传送量
    • 控制总线 的宽度决定了CPU对系统中其它器件的控制能力

    地址总线:
    N跟地址线,宽度位N,即2的N次方个内存单元
    数据总线:
    一根数据总线可以传输一个0或1,即1bit。

    |类别 | 8080 | 8088 | 8086 | 80286 | 80386 |
    |地址总线根数|16 |20 |20 |24 |32 |
    |地址总线宽度|64KB |1MB |1MB |16MB |4GB |
    |数据总线宽度|8 |8 |16 |16 |32 |
    |一次传送数据|1B |1B |2B |2B |4B |

    寄存器

    CPU如何找到程序即将执行指令位置
    -使用寄存器(CS:IP)寻址来确定即将执行指令位置

    寄存器是CPU内的组成部分。有限存储容量的告诉存储部件,可以用来暂存指令、数据和地址。
    -存在于CPU中 用于存储数据 速度快 数量有限

    8086CPU:14个寄存器,所有的寄存器都是16位,可以存放两个字节,即一个字
    80386CPU:16个寄存器,所有的寄存器都是32位,可以存放四个字节,即两个字

    16位CPU所还有的寄存器有(共14个)
    4个数据寄存器(AX、BX、CX、DX)
    2个变址寄存器(SI和DI)
    2个指针寄存器(SP和BP)
    4个段寄存器(ES、CS、SS、DS)
    1个指令指针寄存器(IP)
    1个标致寄存器(Flags)

    32位CPU所含有的寄存器有(共16个)
    4个数据寄存器(EAX、EBX、ECX、EDX)
    2个变址寄存器(ESI和EDI)
    2个指针寄存器(ESP和EBP)
    6个段寄存器(ES、CS、SS、DS、FS和GS)
    1个指令致志寄存器(EIP)
    1个标志寄存器(EFlags)

    64位CPU 使用RAX

    寄存器32位

    通用寄存器共8个:数据寄存器、变址寄存器、指针寄存器
    --用于传送和暂存数据,也可参与算术逻辑运算,并保存运算结果,此外各自具有一些特殊功能。

    数据寄存器(8086--16位)
    主要用来保存操作数和运算结果等信息.
    由AX、BX、CX、DX四个组成
    由于8086之前的CPU位8位CPU,为了兼容以前的8位程序,在8086CPU中,每一个数据寄存器都可以当作两个单独的寄存器来使用,由此,每一个16位寄存器可以当作2个独立的8位寄存器来使用。
    只有数据寄存器可以拆分为独立8位寄存器

    • AX分AH和AL,累加寄存器(Accumulator):可用于乘、除、输入/输出等操作
    • BX分BH和BL,基地址寄存器(Base):可作为存储器指针使用
    • CX分CH和CL,计数寄存器(Count):在循环和字符操作时,要用它来控制循环次数:在位操作中,当移多位时,要用CL来指明移位的位数。
    • DX分DH和DL,数据寄存器(Data):在进行乘、除运算时,它可作为默认的操作数参与运算,也可用于存放I/O的端口地址。

    注意:
    在16位CPU中,AX、BX、CX、DX不能存放存储单元的地址
    在32位CPU中,其32位寄存器EAX、EBX、ECX、EDX不仅可传送数据、暂存数据保存算术逻辑运算结果,而且也可作为指针寄存器,所以这些32位寄存器更具有通用性。

    通常文件中至少有两个段

    • 代码段:存储程序的指令--一般可读、不可写、可执行
    • 数据段:存储程序中要用的数据---一般可读、可写、可执行
    物理地址 = 基础地址 + 偏移地址
    基础地址 = 段地址 * 0x10H
    物理地址 = 段地址*0x10H + 偏移地址
    

    注意:CPU可以用不同的段地址和偏移地址形成同一个物理地址

    段寄存器
    8086CPU有4个段寄存器

    • CS:代码段寄存器(Code Segment)
    • DS:数据段寄存器(Data Segment)
    • SS:栈段寄存器(Stack Segment)
    • ES:附加段寄存器(Extra Segment)
      8086机中,任意时刻,CPU将CS:IP指向的内容作为即将执行的指令

    修改CS:IP

    • CPU是由CS:IP中的内容决定执行命令
    • 修改方法:同时修改CS:IP的内容或修改IP的内容
    1.同时修改CS:IP的内容:jmp 段地址:偏移地址
    2.修改IP的内容:jmp 某一合法寄存器, 好似:mov IP 莫伊合法寄存器
    

    Windows下汇编工具-debug使用

    DOSBox DownLoad
    1.安装DOSBox环境和Debug.exe
    2.配置DOSBox操作目录
    安装目录下 DOSBox 0.74-3 Options.bat 鼠标双击,不可以直接编辑

    [autoexec]
    MOUNT C E:masmpro
    set PATH=$PATH$;E:masmpro
    

    此外可以动后手动mount。
    具体操作见安装目录用户文档,或intro mount
    配置后,提示挂载成功。
    切换到C: 目录下,dir指令可查看masmpro内文件
    3.Debug.exe
    MS-DOS Command - DEBUG.EXE
    debug是DOS、Windows提供的实模式(8086方式)程序的调试工具。
    debug功能
    可以查看CPU各种寄存器的内容
    可以查看内存的情况
    可以在机器码级别跟踪程序的运行

    常用操作:

    1. R:查看更改cpu寄存器内容
    2. D:查看内存中内容
    3. E:改写内存中的内容
    4. U:将内存中机器指令翻译成汇编指令
    5. T:执行一条机器指令
    6. A:以汇编格式在内存中写入一条指令

    参考 王爽 《汇编语言 第3版》35页

    DOSBox下调试(masm、link、debug)简单的汇编语言程序

    分段管理及标志寄存器

    分段管理

    一个存储单元 有一个物理地址,多个逻辑地址
    物理地址:
    一个存储单元的编号
    每个物理存储单元都有一个20位编号
    8086CPU物理地址范围:00000H~FFFFFH
    逻辑地址
    用户编程时,采用逻辑地址,形式为: 段基地址:段内偏移地址
    将逻辑地址左移4位,加上偏移地址就得到20位物理地址

    段寄存器与逻辑段
    8086CPU有4个段寄存器,每个段寄存器用来确定一个逻辑段的起始位置,每种逻辑段均有各自的用途:
    CS(代码段):指明代码的起始地址
    利用CS:IP取得下一条要执行的指令
    SS(堆栈段):指明堆栈段的起始地址
    利用SS:SP操作堆栈顶的数据
    DS(数据段):指明数据的起始地址
    利用DS:EA存取数据段中的数据
    ES(附加段):指明附加段的起始地址
    利用ES:EA存取附加段中的数据
    EA是偏移地址,称之为有效地址EA
    若操作数在主存中,存取的方法有:

    • 直接寻址方式
    • 寄存器间接寻址方式
    • 寄存器相对寻址方式
    • 基址变址寻址方式
    • 相对机制编制寻址方式

    没有指明段前缀时,一般的数据访问在DS(数据段)
    MOV AX,1000H = MOV AX,DS:[1000H]

    标志寄存器

    标志寄存器
    |标志位| 标志位名称及外语全称 | =1 | =0 |
    |CF | 进位标志/Carry Flag| 进位 | 无进位 |
    |PF | 奇偶标志/Parity Flag| 偶 | 奇 |
    |AF |辅助进位标志/Auxiliary Carry Flag | 进位| 无进位|
    |ZF | 零标志/Zero Flag | 等于零| 不等于零|
    |SF | 符号标志/Sign Flag | 负 | 非负 |
    |TF | 跟踪标志/Trace |||
    |IF | 中断标志/Interrupt Flag| 允许| 禁止 |
    |DF | 方向标志/Direction Flag| 减少| 增加 |
    |OF | 溢出标志/Overflow Flag | 溢出| 未溢出 |

    状态标志
    用于记录程序运行结果的状态信息
    CF ZF SF PF OF AF
    控制标志
    用于控制处理器执行指令
    DF IF TF

    运算结果标志位:
    CF标志(Carry进位,Flag标志):
    进位标志位,一般情况,进行无符号运算时,它记录运算结果的最高位向更高位的进位值,或从更高位的借位值,如果运算结果的最高位产生了一个进位或借位,那么其值为1,否则其值为0。

    ZF标志(ZeroFlag):
    零位标志位,它记录相关指令执行后的结果是否为0,如果是0,那么ZF=1,如果结果不为0,那么ZF=0。

    PF标志(ParityFlag):
    奇偶标志位,它记录相关指令执行后,其结果的目的操作数最低有效位二进制位中1个个数是否为偶数,如果是偶数,PF=1,反之为0。

    SF标志(SignFlag):
    符号标志位,它记录相关指令执行后,其结果是否为负,如果结果为负,SF=1,如果非负,SF=0。

    OF标志(Overflow溢出,Flag标志):
    溢出标志位,在进行有符号数运算的时候,如果结果超出了机器所能表示的范围称为溢出,OF的值被置为1,否则OF的值为0。
    注意:这里所说的溢出,只是对有符号运算而言。
    有符号时,运算结果值不正确。

    AF标志(Auxiliary Carry Flag)
    若运算时D3(低半字节)有进位或借位时,AF=1,否则AF=0;

    状态控制标志位:
    TF标志(TrapFlag):
    追踪标志位,当追踪标志被置为1时,CPU进入单步执行方式,即每执行一条指令产生一个单步中断请求,这中方式主要用于程序的调试。

    IF标志(Interrupt-enable Flag):
    中断允许标志位,用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求,但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。
    当IF=1时,CPU可以相应CPU外部的可屏蔽中断发出的中断请求。
    当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。
    CPU的指令系统中也有专门的指令来改变标志位IF的值。

    DF标志(Direction Flag)
    用于串操作指令中,控制地址的变化方向:
    设置DF为0,存储器地址自动增加
    设置DF为1,存储器地址自动减少

    CLD指令用于复位
    STD指令用于置位

    溢出与进位
    有符号、无符号指的是最高位是否是符号位,即是以补码的形式看待还是以源码的形式看待。
    溢出标志(OF):表示有符号数运算结果是否超出范围,运算结果已经不正确;
    范围:0~255 0~65535
    进位标志(CF):表示有符号数运算结果是否超出范围,运算结果仍然正确
    范围:-128~127 -32768~32767

    指令及寻址方式

    一般来说指令是由两部分组成,即操作码和操作数
    操作码: 给出该指令应完成何种操作
    操作数: 用来描述该指令的操作对象
    在指令中操作码是不可缺少的,但操作数可以没有,也可以有一个操作数或两个操作数

    根据操作数的个数,指令格式可以分为以下几种:
    1.零操作数指令
    指令格式中没有操作数或操作数是隐含约定
    2.一操作数指令
    指令格式中有一个操作数,或还有一个隐含的操作数(实际上是双操作数)
    3.二操作数指令
    指令中有两个操作数,其中一个为 目的操作数,另一个为源操作数

    源操作数:只能读取的操作数
    目的操作数:即可读取也可写入(存放操作结果)的操作数

    七种寻址方式

    指令中指明操作数存放位置的表达方式

    寻址方式可以分为:

    • 立即数寻址方式
    • 寄存器寻址方式
    • 存储器寻址方式
      • 直接寻址方式
      • 寄存器间接寻址方式
      • 寄存器相对寻址方式
      • 基址加变址寻址方式
      • 相对加基址变址寻址方式

    指令中数据存放的位置,三种:
    1.存放指令中(立即数)
    操作数包含在指令中,即被曹祖数据直接表示在指令的操作数字段中,紧跟在操作码之后。
    2.存放于寄存器中(寄存器操作数)
    数据存放在CPU的一个寄存器中
    3.存放于存储器中(存储器操作数)
    数据在内存中或在I/O端口中,存放数据的偏移地址以某种方式表示在指令中。
    例如 MOV AX,[2500H] 其中[2500H]为存储器操作数
    存储器操作数中操作数字段至少此操作数的偏移地址,而段地址有某个段寄存器来提供。此例中默认为数据段DS

    立即数寻址
    操作数为立即数,直接存放在指令的操作数字段中。
    立即数寻址时,只允许源操作数为立即数,目标操作数必须是寄存器或存储器,其作用时给寄存器或存储单元赋值。
    在汇编中,立即数不能作为指令中的第一操作数。

    寄存器寻址
    操作数在指令所指示的寄存器中
    表示格式:直接在指令中写出寄存器名称

    存储器寻址

    • 直接寻址方式
    • 寄存器间接寻址方式
    • 寄存器相对寻址方式
    • 基址加变址寻址方式
    • 相对加基址变址寻址方式

    直接寻址
    操作数存在内存中,操作数的偏移地址直接表示在指令中
    表示格式:[偏移地址]
    默认操作数存放在内存的数据段中
    MOV AL,[1964H]

    段超越
    操作数也允许存放在其他段中(ES,SS),此时应该在指令中指明段超越
    :若操作数不在指令默认的段中,而在其它莫格段中,则需要在指令中加以表示,这种情况称为段超越。
    MOV AL,ES:[1064H]

    间接寻址方式
    操作数存在存储器中国,操作数的偏移地址在BX、SI、DI和BP的某个寄存器中。
    若以BX、SI、DI作为间接寻址寄存器,则默认操作数存放在数据段中,用DS寄存器中的内容作为地址
    若以BP作为间接寻址寄存器,则默认操作数存放在堆栈段中,用SS寄存器中的内容作为地址。

    相对寻址方式
    操作数在存储器中,操作数的有效地址是一个基址寄存器(BX、BP)或变址寄存器(SI、DI)的内容加上指令中给定的8位或16位位移量之和。

    基址加变址寻址方式
    在基址加变址寻址方式中,通常把BX和BP看作是基址寄存器,把SI和DI看作是变址寄存器。把两种方式组合起来形成一种新的寻址方式。
    基址加变址的寻址方式是把一个基址寄存器BX或BP的内容,加上变址寄存器SI或DI的内容,并以一个段寄存器作为地址基准,作为操作数的地址。

    相对基址加变址寻址方式
    在相对基址变址寻址方式中,通常把BX和BP看作是基址寄存器,把SI和DI看作是变址寄存器。它是把一个机制寄存器BX或BP的内容,加上变址寄存器SI或DI的内容,再加上指令中给定的8位或16位位移量,并以一个段寄存器作为地址基准,作为操作数的地址。

    常见的汇编指令

    数据传送指令

    包括:

    • 通用传送指令;
    • 累加器专用传送指令
    • 地址传送指令
    • 标志传送指令

    通用传送指令;所有通用传送指令都不影响标志位
    1)基本传送指令(MOV)
    指令格式 MOV DST,SRC
    源操作数和目的操作数可用6中寻址方式的任何一种
    操作:将SRC内容赋给DST

    注意:
    存储器操作数之间不能直接传送
    立即数不能直接传送段寄存器
    段寄存器之间不能直接传送
    CS只可以作为源操作数
    源操作数和目的操作数的宽度必须相同

    汇编-数据传送路径

    1. 堆栈指令(PUSH 、POP)
      堆栈(STACK)
      数据的存储按后进先出(Last In First Out -- LIFO)原则组织的一段内存区域。

    入栈指令(PUSH)
    格式 PUSH src
    操作过程分两步完成:

    1. (SP)<-(SP) - 2
    2. ((SP)+1,(SP)) <- (src)
      功能:把一个字压入由SP指向的堆栈区

    出栈指令(POP)
    格式 POP dst;
    操作:
    1.(dst)<-((SP)+1, (SP))
    2.(SP) <-(SP) + 2
    功能:把Sp所执行的堆栈顶部的一个字送入目的地址,同时进行修改堆栈指针。

    堆栈用途:
    1.存放寄存器或存储器中暂时不使用的数据,再使用这些数据时可方便地将其弹出。
    2.调用子程序或发生中断时要保护断点信息(入栈),子程序或中断返回时恢复断点信息(出栈)

    断点信息:程序断点地址、标志寄存器及其它能被子程序使用和改变的寄存器。

    注意:
    1.堆栈操作都按字操作;
    2.PUSH、POP指令的操作数可以是CPU内部寄存器或存储单元;
    3.PUSH CS 合法,POP CS 非法;
    4.执行PUSH指令,(SP)-2 ->(SP),低字节放在低地址,高字节放在高地址;
    5.SP总是指向栈顶;
    6.堆栈最大容量即为SP的初值与SS之差。

    3)交换指令(XCHG)
    格式:XCHG dst,src ; (dst)<->(src)
    可以实现:寄存器之间、寄存器和存储器之间
    注意:
    存储器之间不能直接交换
    段寄存器不能作为操作数
    运行字或字节操作。

    累加器专用传送指令;
    1)输入指令(IN)
    功能:用于CPU从外设端口接收数据
    具体形式:
    IN AL,data8; 从8位端口地址输入一个字节
    IN AX,data8; 从8位端口地址输入一个字
    IN AL,DX; 从16位端口地址输入一个字节
    IN AX,DX; 从16位端口地址输入一个字

    2)输出指令(OUT)
    功能:用于CPU向外设端口发送数据
    具体形式:
    OUT data8,AL; 向8位端口地址输出一个字节
    OUT data8,AX; 向8位端口地址输出一个字
    OUT DX,AL; 向16位端口地址输出一个字节
    OUT DX,AX; 向16位端口地址输出一个字

    地址传送指令;
    1)LEA (Load Effective Address)
    格式: LEA reg16,mem
    reg16---16位通用寄存器;
    mem---存储单元;
    功能:将源操作数的偏移地址传送到目的操作数
    注意:源操作数必须以寄存器间接寻址、变址寻址、基址加变址寻址等方式表示的存储器操作数;
    目的操作数位一个16位的通用寄存器。

    2)LDS
    格式:LDS reg16,mem;
    功能:把源操作数指定的4个相继字节的数据分别送指令指定的寄存器及DS寄存器中。
    (reg16) <- (mem)
    (DS) <- ((mem) + 2)

    3)LES

    标志传送指令
    1)LAHF(Load AH into flags)
    格式:LAHF;
    功能:标志寄存器低八位 -> (AH)

    2)SAHF(Store AH into flags)
    格式:SAHF
    功能:(AH)送标志寄存器低八位

    3)PUSHF (Push Flags)
    格式:PUSHF;
    功能:标志进栈

    4)POPF (Pop Flags)
    格式:POPF
    功能:标志出栈

    算术运算指令
    包括:加法指令、减法指令、乘法指令、除法指令
    1.加法指令
    8086具有5条加法指令:

    • ADD(Addition)加法指令
    • ADC(Add with Carry)带进位加法指令
    • INC(Increment)加1指令
    • AAA(ASCII adjust for addition)加法ASCII调整指令
    • DAA(Decimal adjust for addition)加法十进制调整指令
      2、减法指令
      8086有7条减法指令:
    • SUB(Subtraction)减法指令
    • SBB(SubtractionwithBorrow)进位减法指令
    • DEC(Decrement by 1)减1指令
    • NEG(Negate) 求补指令
    • CMP(Compare)比较指令
    • AAS(ASCII Adjust for Subtraction) 减法ASCII调整指令
    • DAS(Decimal Adjust for Subtraction) 减法十进制调整指令
    1. 乘法指令
      1)无符号乘法(MUL)
      2)带符号乘法(IMUL)

    4、除法指令
    1)无符号除法(DIV)
    2)带符号除法(IDIV)
    3)字节扩展指令(CBW)
    4)字扩展指令( CWD

    5、十进制调整指令(略)
    共六条

    • AAA非压缩BCD码的加法十进制调整
    • DAA压缩BCD码的加法十进制调整
    • AAS非压缩BCD码的减法十进制调整
    • DAS压缩BCD码的减法十进制调整
    • AAM乘法的十进制调整
    • AAD除法的十进制调整

    位操作类指令
    1)逻辑运算指令
    •AND逻辑“与”指令
    •TEST测试指令
    •OR逻辑“或”指令
    •XOR(eXclusive OR)逻辑“异或”指令
    •NOT逻辑“非”指令

    2)移位指令
    共有以下8条
    •SAL (Shift Arithmetic Left)算术左移
    •SAR (Shiftarithmeticright)算术右移
    •SHL (Shift logical left)逻辑左移
    •SHR (Shiftlogicalright)逻辑右移
    •ROL (Rotateleft)循环左移
    •ROR (Rotateright)循环右移
    •RCL (Rotateleftwith carry)带进位循环左移
    •RCR (Rotateright withcarry)带进位循环右移

    ROL:循环左移,高位到低位并送CF
    ROR:循环右移,低位到高位并送CF
    RCL:循环左移,进位值(原CF)到低位,高位进CF
    RCR:循环右移,进位值(原CF)到高位,低位进CF

    “串”就是内存中一段地址相连的字节或字;
    •串操作,也叫数据块操作;
    •可实现存储器数据间的直接传送;
    •8086有5种基本串操作:B/W 字节/字
    MOVS(Move string)串传送指令
    CMPS(Compare string)串比较指令
    SCAS(Scan string)串扫描指令
    LODS(Load from string)取串指令
    STOS (Store in to string)存串指令

    (一)标志处理指令
    •CLC (Clearcarryflag)清C标志
    •STC(Setcarryflag )置C标志
    •CMC(Complementcarryflag)对C求反
    •CLD(Cleardirectionflag)清D标志
    •STD(Setdirectionflag)置D标志
    •CLI(Clearinterruptflag)清I标志
    •STI (Setinterruptenableflag)置I标志

    (二)其他处理机控制指令
    •NOP(Nooperation)空操作
    •HLT(Halt) CPU暂停状态
    •WAITCPU等待状态
    •ESC交权
    •LOCK(Lockbus)总线锁定

    指令REPE、REPZ和REPNE、REPNZ
    无条件转移 JMP
    有条件转移

    过程(子过程)调用命令
    CALL RET

    循环控制指令
    无条件循环 LOOP 语句标号 判断CX值是否为0
    条件循环
    LOOPZ/LOOPE 语句标号
    LOOPNZ/LOOPNE 语句标号

    中断指令
    INT n n--中断号,0~255
    中断返回 IRET

    OPCode 操作码(Operation Code)

    描述机器语言指令中,指定要执行某种操作的机器码。
    OpCode与汇编指令的关系:

    • 一个OpCode不知对应一个指令
    • 一个指令不知对应一个OpCode
  • 相关阅读:
    九大经典算法之插入排序、希尔排序
    1072 开学寄语 (20 分)
    1070 结绳 (25 分
    查找字符串中的所有数字
    通过类继承计算梯形面积
    将命令的输出生成一个Web页面
    从Internet下载一个文件
    使用Excel管理命令输出
    将一个命令的输出保存到CSV文件
    使用属性存储用户编号和姓名
  • 原文地址:https://www.cnblogs.com/yongchao/p/13324780.html
Copyright © 2011-2022 走看看