C++ 逆向辅助学习----汇编基础 学习指令集原理与call原理跟使用 5

61 篇文章 2 订阅
17 篇文章 2 订阅

[bx]和loop指令
    1.[bx]和内存单元的描述
        1.1 [bx]是什么呢?
            和[0]有些类似,[0]表示内存单元,它的偏移地址是0。

        1.2 我们要完整地描述一个内存单元,需要两种信息:
            (1)内存单元的地址;
            (2)内存单元的长度(类型)。
            我们用[0]表示一个内存单元时,0 表示单元的偏移地址,
            段地址默认在ds中,单元的长度(类型)可以由具体指令中的
            其他操作对象(比如说寄存器)指出。
 
        1.3 [bx]同样也表示一个内存单元,它的偏移地址在bx中,
            比如下面的指令:
            mov ax,[bx]
            mov al,[bx]

    2.loop指令(循环指令)
        2.1 指令的格式是:loop 标号,CPU 执行loop指令的时候,要进行两步操作:
             ① (cx)=(cx)-1;
             ② 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行。

        2.2 从上面的描述中,我们可以看到,cx中的值影响着loop指令的执行结果。
            通常(注意,我们说的是通常)我们用loop指令来实现循环功能,
            cx 中存放循环次数。

        2.3 从上面的过程中,我们可以总结出用cx和loop 指令相配合实现循环
            功能的三个要点:
            (1)在cx中存放循环次数;
            (2)loop 指令中的标号所标识地址要在前面;
            (3)要循环执行的程序段,要写在标号和loop 指令的中间。

        2.4 用cx和loop指令相配合实现循环功能的程序框架如下:
               mov cx,循环次数
               s:循环执行的程序段
               loop s

         问题分析:5.2
        
            //循环了236次
            assume cs:code
            code segment
                mov ax,0
                mov cx,236
              s:add ax,123
                loop s

                mov ax,4c00h
                int 21h
            code ends
            end
            
           //循环了123次
            assume cs:code
            code segment
                mov ax,0
                mov cx,123
              s:add ax,236
                loop s

                mov ax,4c00h
                int 21h
            code ends
            end

    3.loop和[bx]的联合应用
        在实际编程中,经常会遇到,用同一种方法处理地址连续的
        内存单元中的数据的问题。
        
        我们需要用循环来解决这类问题,同时我们必须能够在每次循环
        的时候按照同一种方法来改变要访问的内存单元的地址。

        这时,我们就不能用常量来给出内存单元的地址
        (比如[0]、[1]、[2]中,0、1、2是常量),而应用变量。
        
        “mov al,[bx]”中的 bx就可以看作一个代表内存单元地址的变量,
        我们可以不写新的指令,仅通过改变bx中的数值,改变指令访问的内存单元。

        
     4.段前缀
        指令“mov ax,[bx]”中,内存单元的偏移地址由bx给出,
        而段地址默认在ds中。
        
        我们可以在访问内存单元的指令中显式地给出内存单元
        的段地址所在的段寄存器。

        这些出现在访问内存单元的指令中,用于显式地指明内存单元的段
        地址的“ds:”、“cs:”、“ss:”或“es:”,在汇编语言中称为段前缀。
        

六、更灵活的定位内存地址的方法
    1 and和or指令        
        (1)and 指令:逻辑与指令,按位进行与运算。
            如 mov al, 01100011B
               and al, 00111011B
          执行后  al = 00100011B
        通过该指令可将操作对象的相应位设为0,其他位不变。
        例如: al = 1111 1111B
          将al的第6位设为0:  and al,1011 1111B
          将al的第7位设为0:  and al,0111 1111B
          将al的第0位设为0:  and al,1111 1110B          
       
         同C语言里面的"&"
        
         (2)or 指令:逻辑或指令,按位进行或运算
             如 mov al, 01100011B
                 or al, 00111011B
           执行后  al = 01111011B
           通过该指令可将操作对象的相应位设为1,其他位不变。
           例如:al = 0000 0000B
           将al的第6位设为1:  and al,0100 0000B
           将al的第7位设为1:  and al,1000 0000B
           将al的第0位设为1:  and al,0000 0001B        
          
          同C语言里面的"|"
       
    2.[bx+idata]  
        在前面,我们可以用[bx]的方式来指明一个内存单元,
        我们还可以用一种更为灵活的方式来指明内存单元:
       
        [bx+idata]表示一个内存单元,它的偏移地址为(bx)+idata
        (bx中的数值加上idata)。

        我们看一下指令mov ax,[bx+200]的含义:
        将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),
        存放一个字,偏移地址为bx中的数值加上200,段地址在ds中。
        数学化的描述为: (ax)=((ds)*16+(bx)+200)

     3.SI和DI
       SI和DI是8086CPU中和bx功能相近的寄存器,
       SI和DI不能够分成两个8 位寄存器来使用。
       下面的三组指令实现了相同的功能:
        (1) mov bx,0
              mov ax,[bx]
        (2) mov si,0
              mov ax,[si]
        (3) mov di,0
              mov ax,[di]

         (4) mov bx,0
              mov ax,[bx+123]
         (5) mov si,0
              mov ax,[si+123]
         (6) mov di,0
              mov ax,[di+123]

     4. [bx+si]和[bx+di]    
          在前面,我们用[bx(si或di)]和[bx(si或di)+idata] 的方式来指明
          一个内存单元,我们还可以用更灵活的方式:
            [bx+si]
            [bx+di]

            [bx+si]表示一个内存单元,它的偏移地址为(bx)+(si)(即bx中的数值加上si中的数值)。
            
     5. [bx+si+idata]和[bx+di+idata]  
        [bx+si+idata]表示一个内存单元
           它的偏移地址为(bx)+(si)+idata。
          (即bx中的数值加上si中的数值再加上idata)


     6.如果我们比较一下前而用到的几种定位内存地址的方法(可称为寻址方式),
       就可以发现有以下几种方式:
        (1)[iata] 用一个常量来表示地址,可用于直接定位一个内存单元;
        (2)[bx]用一个变量来表示内存地址,可用于间接定位一个内存单元;
        (3)[bx+idata] 用一个变量和常量表示地址,可在一个起始地址的基础上用变量间接定位一个内存单元;
        (4)[bx+si]用两个变量表示地址;
        (5)[bx+si+idata] 用两个变量和一个常量表示地址。
            直接寻址
            寄存器间接寻址
            寄存器相对寻址
            基址变址寻址
            相对基址变址寻址
            

七、转移指令的原理
       8086CPU的转移指令分为以下几类:
       无条件转移指令 (如:jmp)
       条件转移指令
       循环指令(如:loop)
       过程   (函数调用)
       中断  
        
     1.jmp 指令
        jmp为无条件转移,可以只修改IP,也可以同时修改CS和IP;
        jmp指令要给出两种信息:
          转移的目的地址
          转移的距离(段间转移、段内短转移,段内近转移)

           
        (1)jmp short 标号(转到标号处执行指令)
         这种格式的 jmp 指令实现的是段内短转移,它对IP的修改范围为
         -128~127,也就是说,它向前转移时可以最多越过128个字节,
         向后转移可以最多越过127个字节。

         assume cs:codesg
        codesg segment
          start:mov ax,0
                  jmp short s
                  add ax,1
               s:inc ax
        codesg ends
        end start

           左面的程序执行后, ax中的值为 1 ,因为执行  jmp short s 后 ,
           越过了add ax,1 ,IP 指向了标号 s处的 inc ax。也就是说,
           程序只进行了一次ax加1操作。  

       (2)依据位移进行转移的jmp指令
         jmp short s指令的读取和执行过程:
        (1)(CS)=0BBDH,(IP)=0006,CS:IP指向EB 03(jmp short s的机器码);
        (2)读取指令码EB 03进入指令缓冲器;
        (3)(IP)=(IP)+所读取指令的长度=(IP)+2=0008,CS:IP指向add ax,1;
        (4)CPU指行指令缓冲器中的指令EB 03;
        (5)指令EB 03执行后,(IP)=000BH,CS:IP指向inc ax。
       
       注意: 要转移的目的地址是CS:000B,而CPU 执行 EB 03时,当前的(IP)=0008,
            如果将当前的IP值加3,使(IP)=000BH,CS:IP就可以指向目标指令。

         在转移指令EB 03中并没有告诉CPU要转移的目的地址,却告诉了
         CPU 要转移的位移,即将当前的IP向后移动3个字节。

           补码:
                -9的补码怎么算出来的
             +9 原码: 0000  1001       =>09H
            
                反码: 1111  0110
                                 + 1
                       ——————————————
              -9补码:  1111     0111       =>F7H                   
       
       结论:
          CPU执行 jmp short 标号 指令时并不需要转移的目的地址,
          只需要知道转移的位移就行了。
          
         (3) 实际上,指令“jmp short 标号”的功能为(IP)=(IP)+8位位移。
                (1)8位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
                (2)short指明此处的位移为8位位移;
                (3)8位位移的范围为-128~127,用补码表示
                (4)8位位移由编译程序在编译时算出。
      
        
         (4) 指令“jmp near ptr 标号”的说明:
            (1)16位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
            (2)near ptr指明此处的位移为16位位移,进行的是段内近转移;
            (3)16位位移的范围为
               -32769~32767,用补码表示;
            (4)16位位移由编译程序在编译时算出。
            
            
         (5)jmp near ptr 标号
               它实现的时段内近转移。
                指令“jmp near ptr 标号”的功能为:
                (IP)=(IP)+16位位移。
    
               指令“jmp near ptr 标号”的说明:
                (1)16位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
                (2)near ptr指明此处的位移为16位位移,进行的是段内近转移;
                (3)16位位移的范围为
                   -32769~32767,用补码表示;
                (4)16位位移由编译程序在编译时算出。
     
         (6)指令 “jmp far ptr 标号”
                实现的是段间转移,又称为远转移。

                指令 “jmp far ptr 标号” 功能如下:
                (CS)=标号所在段的段地址;
                (IP)=标号所在段中的偏移地址。
                far ptr指明了指令用标号的段地址和偏移地址修改CS和IP。
            
              
          (7) 指令格式:jmp 16位寄存器
             功能:IP =(16位寄存器)
             这种指令我们在前面的课程(参见2.11节)中已经讲过,这里就不再详述。
    
          (8)转移地址在内存中的jmp指令有两种格式:
                (1) jmp word ptr 内存单元地址(段内转移)
                    功能:从内存单元地址处开始存放着一个字,是转移的目的偏移地址。
                    
                    内存单元地址可用寻址方式的任一格式给出。        
            
                mov ax,0123H
                mov ds:[0],ax
                jmp word ptr ds:[0]
                执行后,(IP)=0123H

            
                mov ax,0123H
                mov [bx],ax
                jmp word ptr [bx]
                执行后,(IP)=0123H

            
                2) jmp dword ptr 内存单元地址(段间转移)
                    功能:从内存单元地址处开始存放着两个字,高地址处的字是转移的目的段地址,
                    低地址处是转移的目的偏移地址。
                        (CS)=(内存单元地址+2)
                        (IP)=(内存单元地址)
                内存单元地址可用寻址方式的任一格式给出。
            
                    mov ax,0123H
                    mov ds:[0],ax
                    mov word ptr ds:[2],0
                    jmp dword ptr ds:[0]
                    执行后,
                    (CS)=0
                    (IP)=0123H
                    CS:IP指向0000:0123。

            
                    mov ax,0123H
                    mov [bx],ax
                    mov word ptr [bx+2],0
                    jmp dword ptr [bx]
                    执行后,
                    (CS)=0
                    (IP)=0123H
                    CS:IP指向0000:0123。

            
        2. jcxz指令
            (1)jcxz指令为有条件转移指令,所有的有条件转移指令都是短转移,在对应的机器码中
                包含转移的位移,而不是目的地址。对IP的修改范围都为-128~127。
            
                指令格式:jcxz 标号  
                   (如果(cx)=0,则转移到标号处执行。)    
            
            
            (2)jcxz 标号 指令操作:
                - 当(cx)=0时,(IP)=(IP)+8位位移)
                    8位位移=“标号”处的地址-jcxz指令后的第一个字节的地址;
                    8位位移的范围为-128~127,用补码表示;
                    8位位移由编译程序在编译时算出。
                    当(cx)=0时,什么也不做(程序向下执行)。

            
                - jcxz 标号 指令操作:
                    当(cx)=0时,(IP)=(IP)+8位位移)
                    8位位移=“标号”处的地址-jcxz指令后的第一个字节的地址;
                    8位位移的范围为-128~127,用补码表示;
                    8位位移由编译程序在编译时算出。
                    
                    当(cx)!=0时,不进行跳转(程序向下执行)。

                我们从 jcxz的功能中可以看出,指令“jcxz 标号”的功能相当于:
                if((cx)==0)
                    jmp short 标号;
                (这种用C语言和汇编语言进行的综合描述,或许能使你对有条
                件指令理解得更加清楚。)

            
            检测点9.2
            s:mov ch,0
              mov cl,[bx]   
                 jcxz ok       ;当cx=0时,CS:IP指向ok       
              inc bx
            
            
        3.loop指令
           (1) loop指令为循环指令,所有的循环指令都是短转移,在对应的机
               器码中包含转移的位移,而不是目的地址。对IP的修改范围
               都为-128~127。
            
            指令格式:loop 标号
                ((cx))=(cx)-1,如果(cx)≠0,转移到标号处执行。    
            
            (2)loop 标号 指令操作:
                (1)(cx)=(cx)-1;
                
                (2)如果(cx)≠0,(IP)=(IP)+8位位移。
                    8位位移 = “标号”处的地址 - loop指令后的第一个字节的地址;
                    8位位移的范围为-128~127,用补码表示;
                    8位位移由编译程序在编译时算出。
                    
                    当(cx)=0,什么也不做(程序向下执行)
            
                    我们从loop的功能中可以看出,指令“loop 标号”的功能相当于:
                    (cx)--;
                    if((cx)≠0)
                     jmp short 标号

            
             检点的9.3
                inc cx
            
        4. 根据位移进行转移的意义
          前面我们讲到:
             jmp short 标号
             jmp near ptr 标号
             jcxz 标号
             loop 标号
           等几种汇编指令,它们对 IP的修改是根据转移目的
           地址和转移起始地址之间的位移来进行的。在它们
           对应的机器码中不包含转移的目的地址,而包含的起
           始地址到目的地址的位移。
        
           这样设计,方便了程序段在内存中的浮动装配。
    
    
        5.编译器对转移位移超界的检测
            注意,根据位移进行转移的指令,它们的转移范围受到转移位移的限制,
            如果在源程序中出现了转移范围超界的问题,在编译的时候,编译器将
            报错。
 

八、 call 和 ret 指令
     1.ret 和 retf
        (1)ret指令用栈中的数据,修改IP的内容,从而实现近转移;
              CPU执行ret指令时,进行下面两步操作:
                (1)(IP)=((ss)*16+(sp))
                (2)(sp)=(sp)+2

         
        (2)retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移;
             CPU执行retf指令时,进行下面四步操作:
                (1)(IP)=((ss)*16+(sp))
                (2)(sp)=(sp)+2
                (3)(CS)=((ss)*16+(sp))
                (4)(sp)=(sp)+2

            可以看出,如果我们用汇编语法来解释ret和retf指令,则:
            CPU执行ret指令时,相当于进行:
             pop IP
            
            CPU执行retf指令时,相当于进行:
             pop IP
             pop CS

          
            检测点10.1
            
            分析:retf执行后 CS = 1000H  IP:0000H
            
            mov ax,1000H  ;段地址cs入栈
            
            mov ax,0000H  ;偏移地址ip入栈
            
            
            执行retf指令时,相当于进行:
             pop IP
             pop CS
            根据栈先进后出原则,应先将段地址CS入栈,
            再将偏移地址ip入栈
            
          
       2. call 指令
          (1) CPU执行call指令,进行两步操作:
                (1)将当前的 IP 或 CS和IP 压入栈中;
                (2)转移。

              call 指令不能实现短转移,除此之外,call指令实现转移的方法
              和 jmp 指令的原理相同,下面的几个小节中 ,我们以给出转移目
              的地址的不同方法为主线,讲解call指令的主要应用格式。


           (2)call 标号(将当前的 IP 压栈后,转到标号处执行指令)

           (3)CPU执行此种格式的call指令时,进行如下的操作:
                (1) (sp) = (sp) – 2
                        ((ss)*16+(sp)) = (IP)
                        
                (2) (IP) = (IP) + 16位位移
 
            
       3. 依据位移进行转移的call指令
            (1)call 标号
                16位位移 = “标号”处的地址 - call指令后的第一个字节的地址;
                16位位移的范围为 -32768~32767,用补码表示;
                16位位移由编译程序在编译时算出。

            (2)如果我们用汇编语法来解释此种格式的 call指令,则:
               CPU 执行指令“call  标号”时,相当于进行:
                    push IP
                    jmp near ptr 标号           
 
            检测点10.2
            mov ax,0      ;ax=0,ip指向1000:3
            call s        ;ax=0,
                           读取call指令后ip=6, push ip
                           执行后ip指向1000:7
            inc ax        ;被跳过的代码
          s:pop ax        ;ax = 6
            
            答案:ax = 6
            
            
        4. 转移的目的地址在指令中的call指令
            前面讲解的call指令,其对应的机器指令中并没有转移的目的地址 ,
            而是相对于当前IP的转移位移。
            
            指令“call far ptr 标号”实现的是段间转移。
            
            
            CPU执行“call far ptr 标号”这种格式的call指令时的操作:
            (1) (sp) = (sp) – 2
                ((ss) ×16+(sp)) = (CS)
                
                (sp) = (sp) – 2
                ((ss) ×16+(sp)) = (IP)
                
            (2) (CS) = 标号所在的段地址
                (IP) = 标号所在的偏移地址

            
                
            从上面的描述中可以看出,如果我们用汇编语法来解释此种格式的 call 指令,则:
               CPU 执行指令 “call far ptr 标号” 时,相当于进行:
                   push CS
                   push IP
                   jmp far ptr  标号
    
            检测点10.3
            
            mov ax,0        ;ax=0, ip指向1000:3
            call far ptr s  ;读取call之后,ip=8, push cs push ip,ip指向1000:8
                            ;执行call后, ip=9 cs=1000H
            inc ax          ;被跳过的指令
          s:pop ax            ;ax=8H
            add ax,ax       ;ax=10H
            pop bx          ;bx = 1000H
            add ax,bx       ;ax = 1010H            
                            
        答案:ax = 1010H    
        
        出栈时,根据先进后出的原则,先出的为ip=8H,后出的为
        cs=1000H


        5. 转移地址在寄存器中的call指令
             (1)指令格式:call 16位寄存器
                功能:
                    (sp) = (sp) – 2
                    ((ss)*16+(sp)) = (IP)
                    (IP) = (16位寄存器)

             (2)指令格式:call 16位寄存器
                 汇编语法解释此种格式的 call 指令,CPU执行call 16位reg时,相当于进行:
                     push IP
                     jmp 16位寄存器

          检测点10.4
            mov  ax,6    ;ax=6,ip指向1000:3    
            call ax         ;读取call指令后,ip=5,push ip
                         ;执行call指令后,ip=6
            inc ax       ;被跳过的代码
            mov bp,sp    ;
            add ax,[bp]  ;ax = 6 + 5 = 0bH              
            
         "call ax" 是先将该指令后的第一个字节偏移地址ip入栈,
          再转到偏移地址为ax出执行指令        
            
          自己在debug进行跟踪确认
        
       
        6. 转移地址在内存中的call指令
            转移地址在内存中的call指令有两种格式:
               (1) call word ptr 内存单元地址

               (2) call dword ptr 内存单元地址
          
           
           (1) call word ptr 内存单元地址
               汇编语法解释:
                    push IP
                    jmp word ptr 内存单元地址    
            
            
             call word ptr 内存单元地址(示例)
                比如下面的指令:
                 mov sp,10h
                 mov ax,0123h
                 mov ds:[0],ax
                 call word ptr ds:[0]
                执行后,(IP)=0123H,(sp)=0EH

            
            (2) call dword ptr 内存单元地址
                汇编语法解释:
                     push CS
                     push IP
                     jmp dword ptr 内存单元地址
            
            
            call dword ptr 内存单元地址(示例)
             比如,下面的指令:
                  mov sp,10h
                  mov ax,0123h
                  mov ds:[0],ax
                  mov word ptr ds:[2],0
                  call dword ptr ds:[0]
             执行后,(CS)=0,(IP)=0123H,(sp)=0CH

        
     7.call 和 ret 的配合使用
       (1)前面,我们已经分别学习了 ret 和call指令的原理。现在我们看一下,
           如何将它们配合使用来实现子程序的机制。
      
            
            
        (2)可是执行完子程序后,如何让CPU接着call指令向下执行?
            call指令转去执行子程序之前,call指令后面的指令的地址将存储在栈中,
            所以可以在子程序的后面使用 ret 指令,用栈中的数据设置IP的值,
            从而转到 call 指令后面的代码处继续执行    
            
            这样,我们可以利用call和ret来实现子程序的机制。    
            
        (3)子程序的框架:
               标号:
                     指令
                     ret
    
        (4)mul 指令
            mul是乘法指令,使用 mul 做乘法的时候:
            (1)相乘的两个数:要么都是8位,要么都是16位。
                 8 位: AL中和 8位寄存器或内存字节单元中;
                16 位: AX中和 16 位寄存器或内存字单元中。

            
            (2)使用mul座乘法的时候:
                结果
                     8位乘法:AX中;
                    16位乘法:DX(高位)和AX(低位)中。

            (4)    格式如下:
                    mul reg
                    mul 内存单元

           
            (5)内存单元可以用不同的寻址方式给出,比如:
                mul byte ptr ds:[0]
                  含义为: (ax)=(al)*((ds)*16+0);

                mul word ptr [bx+si+8]
                   含义为:
                   (ax)=(ax)*((ds)*16+(bx)+(si)+8)结果的低16位;
                   (dx)=(ax)*((ds)*16+(bx)+(si)+8)结果的高16位;

       8.模块化程序设计
         (1) call 与 ret 指令共同支持了汇编语言编程中的模块化设计。
             在实际编程中,程序的模块化是必不可少的。

         (2) 因为现实的问题比较复杂,对现实问题进行分析时,
             把它转化成为相互联系、不同层次的子问题,是必须的解决方法。

         (3) 而call和ret 指令对这种分析方法提供了程序实现上的支持。利用 call和ret指令,
             我们可以用简洁的方法,实现多个互相联系、功能独立的子程序来解决一个复杂的问题。
       
       
       9.参数和结果传递的问题
          (1)子程序一般都要根据提供的参数处理一定的事务,
             处理后,将结果(返回值)提供给调用者。
       
          (2)其实,我们讨论参数和返回值传递的问题,实际上就是在探讨,
             应该如何存储子程序需要的参数和产生的返回值。

          (3)我们设计一个子程序,可以根据提供的N,来计算N的3次方。
                这里有两个问题:
                (1)我们将参数N存储在什么地方?
                (2)计算得到的数值,我们存储在什么地方?

             子程序:
                说明:计算N的3次方
                参数: (bx)=N
                结果: (dx:ax)=N∧3
                  cube:mov ax,bx
                       mul bx
                       mul bx
                       ret
            注意,我们在编程的时候要注意良好的风格,对于程序应有详细的注释。
            子程序的注释信息应该包含对子程序的功能、参数和结果的说明。
            
            因为今天写的子程序,以后可能还会用到;自己写的子程序,也很可能要给别人使用,
            所以一定要有全面的说明。
           
                       
          (4) 用寄存器来存储参数和结果是最常使用的方法。对于存放参数的寄存器和存放结
              果的寄存器,调用者和子程序的读写操作恰恰相反:          
                - 调用者将参数送入参数寄存器,从结果寄存器中取到返回值;
                - 子程序从参数寄存器中取到参数,将返回值送入结果寄存器。  
                   dw data word   2byte
                   dd data dword  4byte
       
        10.批量数据的传递
            (1)前面的例程中,子程序 cube 只有一个参数,放在bx中。
               如果有两个参数,那么可以用两个寄存器来放,可是如果
               需要传递的数据有3个、4个或更多直至 N个,我们怎样存放呢?
            
            
            (2)寄存器的数量终究有限,我们不可能简单地用寄存器来存放多
               个需要传递的数据。对于返回值,也有同样的问题。
   
            (3)在这种时候,我们将批量数据放到内存中,然后将它们所在内存空间的
               首地址放在寄存器中,传递给需要的子程序。
               
               对于具有批量数据的返回结果,也可用同样的方法。

            (4)将一个全是字母的字符串转化为大写
               A: 65   1000001B
               a: 97   1100001B                
         
               B: 66   1000010B
               b: 98   1100010B                
       
       
        11. 寄存器冲突的问题    

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值