编写 ASCII 字符串的汇编指令

Assembly instruction for writing an ASCII String

我目前正在编写一个汇编例程,但我有些不明白。

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

.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,我想我必须写 $48484845 for(48-->'0' and 45-->'-')

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

movl , (%edi) 

输出是正确的,在文件 .txt 中我读到了字符 0,我只是不明白如何在一条指令中写入多个 ascii 字符。

感谢答案,对不起我的英语不好。

编辑:我发现这个值:

movl 7935149, (%edi)

并且这条指令将写入字符串“-,--”我不是不确定的,“-”的 ASCII 是 45 而“,”是 44...

VAL must be the value which allow me to write on (%edi) the string 000-00. What i have to do? Convert the string in ASCII? I know that '0' in ASCII is 48, i thought i had to write 484845 for(48-->'0' and 45-->'-')

so i thought that the string 000- was equal to 48484845 in ASCII. What am i doing wrong?

你已经很接近了,但是你完全跳过了值在计算机中是如何编码的部分。 movl 将 32 位存储到内存中,内存可以按字节(8 位)寻址,用 ASCII 编码的字符通常存储为一个字节 = 一个 ASCII 字符(即使纯 ASCII 只需要 7 位,所以第 8 位始终为零)。

所以你需要的是值VAL,它将四个字节存储到内存中:48、48、48、45。

但是您的十进制值 48484845 有两个问题,一个,当您检查该值在二进制中的外观时,它是 0000_0010_1110_0011_1101_0001_1110_1101(或十六进制 0x2E3D1ED),而 x86 很小- endian 系统,因此这 32 位将被拆分并作为字节 1110_1101(237 或 0xED)、1101_0001(209 或 0xD1)、1110_0011(227 或 0xE3)和 0000_0010(2 或 0x02)。 little-endian 的意思是,低 8 位先进入内存(地址 edi+0),高 8 位最后进入内存(地址 edi+3)。

因此您需要将三个“48”值放入低 24 位,将值“45”放入高 8 位,即您需要值 48 + 48*256 + 48*256*256 + 45*256*256*256 = 758132784,当您将其转换为十六进制时,它是 0x2D303030*256 会将 "move" 值向上 8 位,因为 28 = 256.

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

BTW movl ,(%edi) 写入 4 个字节(mov 上的 "l" 后缀表示 "long" = 32 位值),因此您正在写入四个字符:48, 0, 0, 0.还有你原来的任务,如果你真的只输出“000-00”,没有别的,那么第二个 movVAL2 应该是 movw [=32=]x3030, 4(%edi) 只写两个字节到内存中,用movl 您将值 0x3030 存储为四个字节 48, 48, 0, 0,即在字符串后添加两个零字节。

然后,如果调用例程确实为字符串缓冲区保留了足够的 space(至少 8 个字节),并且它只将 6 个字节写入磁盘上的文件,则第二个 movl 是无害。如果调用者只有 6 字节缓冲区,那么第二个 movl 是缓冲区溢出错误。