如何使声明工作完美?

时间:2017-09-07 02:21:56

标签: assembly x86-16

我可以用变量值初始化Cx寄存器吗? 如下图所示

MOV Cx, varaible

如果不是,那么如何使用用户输入值动态初始化Cx?请帮忙!

1 个答案:

答案 0 :(得分:3)

不是关于名字,而是关于心理形象。程序集中没有变量。

对于机器,只有寄存器,存储器,地址和访问存储器的指令。 Variables 是程序员的逻辑结构,他决定以这种方式编写代码 - 它将使用内存作为"变量"。但如果他决定不这样做,或者犯了错误,那么它就不会表现得多变,机器也不在乎。

例如,在您的代码中,您为"变量"分配内存。在.data部分:

.Data
var DB ?

这将转换为符号var,它有效地存入内存。它还将保留.data部分中的单个字节,因此接下来定义到那里的任何内容都将在此之后分配。如果您要添加下一行var2 DB 13,则var2地址将等于var + 1。您还可以使用相同的地址创建多个符号,如下所示:

.Data
var:
var2:
    DB ?

通过这样的定义,varvar2符号都指向相同的内存地址。

它可能看起来像你的"变量"心理图像与此兼容,因此我将展示"只是记忆和#34;之间的另一个区别。和"变量":

MOV [var], AL      ; store value in AL into memory at address "var"
; your MOV var, AL without brackets works only in MASM/TASM assemblers
; but it is not valid Intel syntax, I will use brackets for every memory access

这将AL的8位值写入地址var的内存中。到现在为止还挺好。现在你问:

MOV CX, [var]

这将编译并执行,但它不会按预期工作。因为您只将8位写入内存,而var仅保留1个字节。但CX是16位寄存器(由CH组成高8位,CL组成低8位),因此该指令将从地址​​var的内存中读取两个字节。 x86是little-endian,因此当CPU使用16位值时,它将低8位映射为第一个字节(偏移+0),高8位映射为第二个字节(偏移+1)。因此,这将使用CLAL存储的值CH加载var,这些值恰好存在于var2 DB 13之后的内存中。如果您要在var之后添加CH,那么13将等于值CX,因此13*256 + <stored_AL>总值将为{{1} }}。如果存储AL为7,则为CX = 3335(或十六进制格式0D07h,这很好地显示了两个字节值,D = 13,7 = 7 )。

因此,如果要将存储的8位值正确读入CX,则必须将其从8位扩展到16位。如果您使用80386+指令集,则有专门的说明:

MOVZX cx,BYTE PTR [var]    ; zero-extend value ("unsigned" arithmetic)
MOVSX cx,BYTE PTR [var]    ; sign-extend value ("signed" arithmetic)

对于80386之前的CPU,您必须计算这样的值,一种可能的方法是:

XOR cx, cx     ; clear all 16bits of CX to zero
MOV cl, [var]  ; fetch only low 8 bits from memory
; CX is now zero-extended 16 bit value of [var] (like MOVZX)

MOV ch, [var]  ; fetch 8 bit value into upper 8 bits of CX
SAR cx, 8      ; use right shift by 8 bits to sign-extend the value
; CX is now sign-extended 16 bit value of [var] (like MOVSX)
; this code is not optimal on 586+ CPUs, but then use MOVSX

这就是&#34;只是记忆&#34;之间的主要区别。和&#34;变量&#34;,程序集不会保护你,它会让你在变量之外读/写内存,编写正确的代码,考虑数据大小和分配是你的任务/保留足够的记忆。另外手动执行所有指针数学运算,即如果要创建单词数组(16位值),则必须将索引缩放* 2以计算正确的字节地址(而C / C ++将隐藏指针数学你,所以你只做[i],* 2由编译器内部完成。