gpt4 book ai didi

assembly - 如何在汇编中打印字符串的长度

转载 作者:行者123 更新时间:2023-12-04 01:43:32 27 4
gpt4 key购买 nike

我正在使用以下 hello world 程序学习汇编

section .text
global _start ;must be declared for linker (ld)

_start: ;tells linker entry point
mov edx,len ;message length
mov ecx,msg ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel

mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel

section .data
msg db 'Hello, world!', 0xa ;our string
len equ $ - msg ;length of our string

我最初的问题是字符串的长度是什么意思。它是指字符数还是内存中的长度(字节数)?
为了检查这一点,我想打印变量 len。我怎样才能做到这一点?我天真地试图定义新变量
    len2 equ $ - len

然后运行
   mov  edx,len2     ;message length
mov ecx,len ;message to write
mov ebx,1 ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel

尝试打印 len,但这没有打印任何内容。如何打印由 len 表示的数字?

最佳答案

   ...
mov edx,len ;message length

这会使用某种数值加载 edx,例如本例中的 14。 len 是“equ”常量符号,类似于 C 中的 #define
   mov  ecx,msg     ;message to write

这将使用第一个字符的地址加载 ecx ( msg 是标签,指向内存)。
   mov  ebx,1       ;file descriptor (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
...

msg db 'Hello, world!', 0xa ;our string

这定义了 14 个字节的内存,值为 72 ('H'), 101 ('e'), ... 。第一个字节由 msg 标签(它的内存地址)指向。
    len equ $ - msg              ;length of our string

这定义了编译时可见的常量 len。它没有定义任何内存内容,因此您无法在可执行文件中或在运行时找到它(除非使用,例如 mov edx,len ,然后它当然会被编译为该特定指令)。

定义是 $ - msg ,这个上下文中的 $ 作为“当前地址”工作,下一个定义的机器码字节将被编译,所以在这个地方它等于 msg + 14 (我希望我没有正确计算字符数:) )。 ((msg+14) - msg) = 14 = len 定义和标签 msg 之间的内存中定义的字节数。

请注意我如何避免将单词作为变量或字符,ASM 级别较低,因此内存和字节中的标签是更准确的措辞,我希望它会帮助您识别细微的差异。
len2 equ $ - len 之后的 len 因此将值 len2 定义为 (msg+14) (仍然在内存中, len 定义没有添加新字节)减去 len ,即 14 ,因此您有效地定义了 len2 等于 msg

然后:
   mov  edx,len2     ;message length
mov ecx,len ;message to write
...

调用 sys_write 时是否使用指向字符串的指针等于 14(无效的内存引用,该内存区域禁止普通用户代码访问),并且长度等于地址 msg ,这将在 32b linux 上很可能是一些像 0x80004000 的值,即2G 字符输出。
sys_write 自然不喜欢那样,失败,并在 eax 中返回错误代码。

要使用 sys_write 将任何内容输出到控制台,您必须首先将其作为 ASCII(我认为 Ubuntu shell 中默认支持 UTF8,但懒得验证)编码字符串写入内存,并给出该内存的 sys_write 地址和长度字节(对于 UTF8 字符串,字节和字符之间的区别很重要, sys_write 不知道字符,它适用于二进制文件和字节,因此长度是字节数)。

我不打算编写代码来输出数字,因为它有几行长(简化的 printf 实现)并且 SO 对此有几个 Q+A,但我希望我的解释能帮助您理解发生了什么以及它是如何工作的。

如果您只是在学习 ASM,请考虑链接 clib 以获取 printf 可用,或者甚至更好,使用调试器,并直接在调试器中的寄存器中验证值,不要打扰字符串输出,那是一个更高级的主题初始算法,以及基本的流程控制和操作堆栈。在您对基本指令的工作方式以及如何调试代码更加熟悉之后,尝试输出数字将更加容易。

关于assembly - 如何在汇编中打印字符串的长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45367779/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com