交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
3 mov操作
分享
未结
0
1002
李延
LV6
2022-06-01
悬赏:20积分
# 1. 说明 将数据从一个位置复制到另一个位置的指令 这些指令把数据从源位置 复制到目的位置,不做任何变化。MOV 类由四条指令组成:movb、movw、movl、movq 这些指令都执行同样的操作;主要区别在于它们操作的数据大小不同:分别是 1、 2、4 和 8 字节。 | 命令 | 效果 | 传输字符大小 | | ---------- | ------- | --------------------- | | movb S,D | S --->D | 传送单字节 | | movw | | 传送字,也就是双字节 | | movl | | 传送双字,也就是4字节 | | movq | | 传送四字,也就是8字节 | | movabsq | | 传送绝对四字 | ## 2 4种基础mov ## 2.1 movl ### 2.1.1 普通情况 ```asm .LC0: .string "movl %d\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movl $123, %esi call printf movl $0, %eax addq $8, %rsp ret ``` ### 2.1.2 传送大于4字节的内容 ```asm .LC0: .string "movl %d\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movl $922337203685477580, %esi call printf movl $0, %eax addq $8, %rsp ret ``` 我们通过movl 传输一个大于4字节的内容,进行编译。这个时候编译会有警告,并且忽略大于4字节内容。如图 ```shell movl2.s: Assembler messages: movl2.s: 警告:end of file not at end of a line; newline inserted movl2.s:9: 警告:922337203685477580 shortened to 3435973836 ``` 结果如下 ```shell [root@localhost mov]# ./a.out movl -858993460 ``` 我们看到应为我们使用的是 %d进行输出的,表示有符号4字节。所以忽略前面几位后。刚好最高位是1 打印出来就是负数。 ### 2.1.3 寄存器使用 大于4字节接收 ```asm .LC0: .string "movl %d\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movl $922337203685477580, %rsi call printf movl $0, %eax addq $8, %rsp ret ``` 我们如果使用rsi ,也就是 8字节的寄存器,接收数据。编译时,就会出错 ```asm movl3.s: Assembler messages: movl3.s:9: 错误:incorrect register `%rsi' used with `l' suffix ``` ### 2.1.4 寄存器使用 小于4字节接收 同样也会报错,如下: ```shel [root@localhost mov]# gcc movl3-1.s movl3-1.s: Assembler messages: movl3-1.s:9: 错误:`%sil' not allowed with `movl' ``` ## 2.2 movb 传输一个字节 ```asm .LC0: .string "movl %d\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movb $123, %sil call printf movl $0, %eax addq $8, %rsp ret ``` movb就是传输一个字符,单应为%d是格式化,4个字符,所以打印出来的结果不是`123`而是如下: ```sh [root@localhost mov]# ./a.out movl 140730452711035 ``` 也就是说movb只会改变 寄存器最低的8位,其他的几位字符保持原来的内容不变。如果我们先用movl将esi4个字节置为0.就可以得到我们想要的结果 ```asm .LC0: .string "movl %d\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movl $0, %esi movb $123, %sil call printf movl $0, %eax addq $8, %rsp ret ``` 结果: ```shell [root@localhost mov]# ./a.out movl 123 ``` ## 2.3 movw ```asm .LC0: .string "movl %hd\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movw $123, %si call printf movl $0, %eax addq $8, %rsp ret ``` 结果: ``` [root@localhost mov]# ./a.out movl 123 ``` ## 2.4 movq ```asm .LC0: .string "movl %ld\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movq $922337203685477580, %rsi call printf movl $0, %eax addq $8, %rsp ret ``` 结果: ``` [root@localhost mov]# ./a.out movl 922337203685477580 ``` # 3 不同数据源与目标的mov指令 在上面的示例中,我们的数据源都是立即数,而目标都是寄存器。 除了上面的组合外,我们还有一下3种组合 - 内存 --> 寄存器 - 寄存器 --> 寄存器 - 寄存器 --> 内存 # 4 不同长度的数据传输 在之前的示例中,都是对于相同长度的内容传输,那么对于不同长度的内容进行传输,具体如下: ## 4.1 movz 由较短的字节的数据源,传输到较长字节的目标。此时,此时将做前置零扩展 具体命令有: - movzbw 将做了零扩展的字节传送到字 - movzbl 将做了零扩展的字节传送到双字 - movzwl 将做了零扩展的字传送到双字 - movzbq 将做了零扩展的字节传送到四字 - movzwq 将做了零扩展的字传送到四字 测试 ```asm .LC0: .string "movl %ld\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movw $123, %bx movzwq %bx,%rsi call printf movl $0, %eax addq $8, %rsp ret ``` 结果 ```shell [root@localhost mov]# ./a.out movl 123 ``` **注意** 没有movlq 的指令,使用就会报错 ## 4.2 movs 同样是长度扩展,与movz不同的是最高位不是直接扩展0,而是使用原来数据的最高位进行扩展。所以就是说对于有符号的数据我们通过movs进行传输,而无符号的使用movz进行传输。他是有movslq的指令 ```asm .LC0: .string "movl %ld\n" .globl main main: subq $8, %rsp movl $.LC0, %edi movl $-123, %ebx movslq %ebx,%rsi call printf movl $0, %eax addq $8, %rsp ret ``` 结果: ```shell [root@localhost mov]# ./a.out movl -123 ```
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号