编写ASCII字符串的汇编指令

时间:2018-08-31 14:43:02

标签: assembly inline-assembly

我目前正在编写一个汇编例程,但我听不懂。

我必须在文件.txt中写入例如字符串“ 000-00”,例程在此处(例程在堆栈中读取输出文件的指针并在其上写入字符串)(例程是从ac程序调用):

.data
.section .text
.global func

func:
      pushl %ebp
      movl %esp, %ebp

      pushl %edi
      pushl %esi

      movl 12(%ebp), %edi
      movl $VAL, (%edi)
      movl $VAL2, 4(%edi)

      popl %esi
      popl %edi
      popl %ebp
      ret
该行中的

movl $VAL, (%edi) 

VAL必须是允许我在字符串(%edi)上写字符串000-00的值。我该怎么办?将字符串转换为ASCII吗?我知道ASCII中的'0'是48,我想我必须为(48->'0'和45->'-')

写$ 48484845

所以我认为字符串000-等于ASCII中的48484845。我究竟做错了什么?为什么要写:

movl $48, (%edi) 

输出正确,并且在.txt文件中,我读取了charachter 0,我只是不理解如何在一条指令中编写多个ascii charachter。

谢谢,我的英语不好。

编辑:我发现了这个值:

movl $757935149, (%edi)

这条指令将写字符串“-,-”,我不怀疑,“-”的ASCII是45,而“,”是44 ...

1 个答案:

答案 0 :(得分:2)

  

VAL必须是允许我在(%edi)字符串上写的值   000-00。我该怎么办?将字符串转换为ASCII吗?我知道   ASCII中的'0'是48,我以为我必须为(48->'0'写$ 48484845   和45->'-')

     

所以我认为字符串000-等于ASCII中的48484845。什么   我做错了吗?

您非常接近,但是您完全跳过了如何在计算机中对值进行编码的部分。 movl将32位存储到内存中,并且内存可按字节(8位)进行寻址,通常以1字节= 1个ASCII字符的形式存储以ASCII编码的字符(即使纯ASCII只需要7位,因此第8位始终为零)。

因此,您需要的是值VAL,该值将在内存中存储四个字节:48、48、48、45。

但是您的十进制值48484845有两个问题,一个是,当您检查二进制值的形式时,它是0000_0010_1110_0011_1101_0001_1110_1101(或十六进制0x2E3D1ED),而x86是little-endian系统,因此这32位将被拆分并以字节1110_1101(237或0xED),1101_0001(209或0xD1),1110_0011(227或0xE3)和{{1 }}(2或0x02)。小尾数表示低8位首先进入内存(地址0000_0010),高8位最后进入内存(地址edi+0)。

因此,您需要将三个“ 48”值放入低24位,将值“ 45”放入前8位,即您需要将值edi+3转换为十六进制时的值{{1} }。 48 + 48*256 + 48*256*256 + 45*256*256*256 = 758132784会将值“向上”移动8位,因为2 8 = 256。

现在,如果您要注意那些十六进制值,您可能会注意到每个十六进制数字都是从正好4位构建的(而十进制0..9数字分布在与上一位/下一位数字共享的4位上,因此它们很难从二进制文件中进行组合/提取),并且使用0x2D303030值实际上可以从头读取它,并将单独的字节视为2D_30_30_30,并且由于这些字节将以低位字节序存储在内存中,内存将设置为四个字节(十六进制):*256,当以ASCII字符串读取时将形成0x2D303030。因此,如果您需要在要设置特定位的位置定义一些常量,而又不想使用计算器或在源代码中进行写入(48 + 48 * 256),则通常可以通过以十六进制格式进行定义来避免这种情况,例如例如30 30 30 2D设置16位值的最高位和最低位,并且每个两个六位数字正好形成一个字节(8位),因此您可以在十六进制格式中看到较大类型的单独字节值(例如word / dword / qword)(顺便说一句,0x8001是十进制的32769,这是我可以在头脑中计算出的值,因为自从8位计算机编程以来,我已经在内存中印上了两个的前16次幂,所以最高位是2 15 = 32768,最低位是2 0 = 1 ...,但是十六进制格式对于此类任务更加简单和方便。)

BTW "000-"写入4个字节(0x8001上的“ l”后缀表示“ long” = 32位值),因此您要写入四个字符:movl $48,(%edi)。同样,这也是您的原始任务,如果您只输出“ 000-00”,而不输出其他任何内容,那么第二个mov48, 0, 0, 0应该是mov,以便仅将两个字节写入内存, VAL2将值movw $0x3030, 4(%edi)存储为四个字节movl,即在字符串后添加两个零字节。

如果调用程序例程确实为字符串缓冲区保留了足够的空间(至少8个字节),并且仅将6个字节写入磁盘上的文件,则第二个0x3030是无害的。如果调用方只有6个字节的缓冲区,则第二个48, 48, 0, 0是缓冲区溢出错误。