编写 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”,没有别的,那么第二个 mov
和 VAL2
应该是 movw [=32=]x3030, 4(%edi)
只写两个字节到内存中,用movl
您将值 0x3030
存储为四个字节 48, 48, 0, 0
,即在字符串后添加两个零字节。
然后,如果调用例程确实为字符串缓冲区保留了足够的 space(至少 8 个字节),并且它只将 6 个字节写入磁盘上的文件,则第二个 movl
是无害。如果调用者只有 6 字节缓冲区,那么第二个 movl
是缓冲区溢出错误。
我目前正在编写一个汇编例程,但我有些不明白。
我必须在文件 .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”,没有别的,那么第二个 mov
和 VAL2
应该是 movw [=32=]x3030, 4(%edi)
只写两个字节到内存中,用movl
您将值 0x3030
存储为四个字节 48, 48, 0, 0
,即在字符串后添加两个零字节。
然后,如果调用例程确实为字符串缓冲区保留了足够的 space(至少 8 个字节),并且它只将 6 个字节写入磁盘上的文件,则第二个 movl
是无害。如果调用者只有 6 字节缓冲区,那么第二个 movl
是缓冲区溢出错误。