2017-07-28 44 views
0

我学习组件使用以下的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代表的号码?

+5

您可能需要检查[**如何在汇编NASM中打印数字**](https://stackoverflow.com/questions/8194141/how-to-print-a-number-in-assembly- nasm)简短的回答是你写*字符*到'stdout'。数字是一个十进制值,而不是可以立即写入的字符串,您必须将整数或无符号值转换为其字符表示形式,然后将其写入'stdout'。 –

+0

出于好奇,你编程的操作系统是什么?视窗? Unix的?苹果系统?我在问,因为在这样的问题之上,经常有人问这个问题是否使用了错误平台的教程。 –

+0

谢谢。我正在使用Ubuntu。出于好奇,当我尝试直接使用stdout打印数字时,我什么也没有得到。为什么它不打印什么,而不是打印一些废话? –

回答

0
... 
    mov edx,len  ;message length 

这会加载edx带有某种数值,如14这种情况下。 len是“当量”恒定符号,像在#define C.

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 $ - lenlen后也这样定义len2(msg+14)len这是14(仍然存在于内存中,通过定义len不添加任何新的字节),让你有效地定义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(我觉得UTF8默认情况下,在Ubuntu外壳支持,但懒得去核实)编码字符串,并赋予该内存的sys_write地址安慰和字节长度(UTF8字符串字节和字符之间的差异很重要,sys_write不知道字符,它与二进制文件和字节一起工作,所以长度是字节量)。

我不会写代码输出数字,因为这是几行(实现简化的printf),SO有几个Q + A,但我希望我的解释能帮助你理解发生了什么,以及如何有用。

如果你刚开始学习ASM,认为无论是链接到的clibprintf可用的,甚至更好,使用调试器和调试器在寄存器中直核实值,不串输出困扰了,这是一个有点更高级的话题,然后是最初的算法,以及基本的流量控制和操作堆栈。在你更熟悉基本指令的工作方式以及如何调试代码之后,然后尝试输出数字会更容易。