输出数据寄存器值在NASM

新人在这里,我已经有一个问题。

我正在修改Jeff Duntemann的汇编书籍中使用的示例代码,我想打印出存储在数据寄存器中的整数值给terminal?

下面的代码是下面的代码,它打印出来的string好吧,在ECX中推送值没关系,但是当它到达以下内容:

pop ecx mov eax,4 mov ebx,1 mov edx, ecx int 80h 

它不会在terminal上显示edx的内容,但我想我已经告诉过mov eax,4等了。

任何人都可以给我任何“指示”(双关语)?

供参考的代号(于2012年6月17日修订):

 SECTION .data submessage: db "I am subtracting 5 from 10!", 10 msglen: equ $-submessage ansmsg: db "Answer is:", 10 msglen2: equ $-ansmsg EOL: db 10 SECTION .bss msg: resd 2 ; reserve space for 2 dwords SECTION .text global _start _start: nop ;Displays test on shell mov eax,4 ;print to terminal mov ebx,1 mov ecx, submessage mov edx, msglen int 80h ;"I am subtracting 5 from 10!" mov eax,4 ;print to terminal mov ebx,1 mov ecx, ansmsg mov edx, msglen2 int 80h ;"Answer is..." ;Subtraction operation below: mov edx, 10 sub edx, 5 mov [msg], edx ; store 5 in msg ; now we need to print msg to terminal mov eax, 4 ;print to terminal mov ebx, 1 mov dword [msg+1], 0xa ;helps prints something out! ;Encountered problem here= prints out 'Answe' instead of integer '5' push dword 2 ; store size of msg push dword [msg] ; push to stack contents of msg int 80h add esp, 3 ;clean stack (2 push calls *4) int 80h ; I like labels :) sys_exit: mov eax,1 ;exit status mov ebx,0 int 80h nop 

PS-如果我的线缩进糟透了,我想知道我该如何改进它; 恕我直言,学习大会得到更多的吸引力,一旦你克服了最初的学习“驼峰”:)

首先,感谢这个问题 – 它促使我在int 80h学习,这是我以前不熟悉的。

你的程序以目前的形式做什么? 它打印什么? 如果我在头脑中正确执行它,我期望它打印第一条消息,然后崩溃。 由于缓冲,它可能甚至不会在可疑的崩溃之前显示第一条消息。

int 80h / eax = 4映射到write()函数。 运行“man 2 write”来获取完整的文档。 函数原型是:

 ssize_t write(int fd, const void *buf, size_t count); 

所以,eax = 4,ebx = fd,ecx = buf,edx = count。 如果你想对你的代码注释更迂回,“mov eax,4”意思是“写一个字符串到文件”,而“mov ebx,1”的意思是“指定文件#1,映射到STDOUT(终端)” 。

我期望第一个int 80h调用来打印一些东西。 第二个int 80h调用是可疑的。 此时eax和ebx保持不变。 但是,edx也是不变的,它保存了第一个字符串的字符串长度。 更有问题的是,你把价值5进入ecx。 ecx保存一个指向要写入的字符串的指针 ,而不是要写入的值。 所以,当你把5放在这里,并调用中断,int将尝试打印从地址0x00000005开始的字符串。 这几乎肯定会导致段错误(崩溃)。

另外,如果我正确读取int 80h文档,则示例中的push / pop堆栈操作没有任何相关性。

以字符串形式打印数字在ASM中有点麻烦。 你需要将数字转换成一个字符串,然后你可以使用int 80h来打印它。 如果你只是想打印一个数字,这是一个你可以作弊的方法:

  • 在.data节中,声明一个名为int2char的新字节:'int2char:db 0'
  • 从ecx减去5后,将数字转换为ASCII加入48(这会给你5而不是5)
  • 将ecx存储到int2char中
  • 将int2char的地址移到ecx中
  • 设置edx为1,因为你只想打印1个字符

一旦你得到这个工作,转换数字与多个数字将作为一个练习。

祝你好运!

我认为推送信息是相关的。 这里是“hello world”程序的另一个例子。

 section .text global _start ;must be declared for linker (ld) _syscall: int 0x80 ;system call ret _start: ;tell linker entry point push dword len ;message length push dword msg ;message to write push dword 1 ;file descriptor (stdout) mov eax,0x4 ;system call number (sys_write) call _syscall ;call kernel ;the alternate way to call kernel: ;push eax ;call 7:0 add esp,12 ;clean stack (3 arguments * 4) push dword 0 ;exit code mov eax,0x1 ;system call number (sys_exit) call _syscall ;call kernel ;we do not return from sys_exit, ;there's no need to clean stack section .data msg db "Hello, world!",0xa ;our dear string len equ $ - msg ;length of our dear string 

现在,我没有写上面的代码,它来自这里:

http://www.cin.ufpe.br/~if817/arquivos/asmtut/index.html#helloworld

所以你可以看到这个作者能够将值移动到堆栈上并调用内核例程,这个例程会将参数从堆栈中取出。 这实际上对我来说更有意义,因为我认为这就是params传递给c函数的方式。 通过特定的寄存器传递参数是没有意义的。 如果一个方法有30个参数,如何通过寄存器传递呢?

在任何情况下,我已经编译了上面的代码,将其链接到我的MacBook Pro上,它运行良好。

无论如何,就像上面的例子一样好,它并没有教你很多。 在这里,我认为,如何从寄存器打印任意值是一个更好的例子。

所以我想要的不是一个预定义的字符串,而是一个真正的编程结构; 一个变量。

很简单,您可以通过执行以下操作来定义一个32位变量:

 section .bss msg: resd 2 

这给了我一个名为“味精”,我可以存储的东西变量(或内存位置)。 通过用resd声明,我正在定义我想保留的双字的数量。 一个双字是32位,所以我声明我要保留2个双字。 为什么2? 我会马上告诉你的。

到现在为止还挺好。

现在我所需要做的就是将一个值移入该内存位置,并按照来自hello,world的示例进行操作。 所以我编码了这个:

 section .text global _start ;must be declared for linker (ld) _syscall: int 0x80 ;system call ret _start: ;tell linker entry point mov dword [msg], 'h' ;move the letter h into my memory location mov dword [msg+1], 0xa ;this is so important, but other author's gloss over it ; the line terminator is essential in order to ; print something out push dword 2 ;message length push dword msg ;message to write push dword 1 ;file descriptor (stdout) mov eax,0x4 ;system call number (sys_write) call _syscall ;call kernel ;the alternate way to call kernel: ;push eax ;call 7:0 add esp,12 ;clean stack (3 arguments * 4) push dword 0 ;exit code mov eax,0x1 ;system call number (sys_exit) call _syscall ;call kernel ;we do not return from sys_exit, ;there's no need to clean stack section .bss msg: resd 1 

所以没有太多改变。 我添加了.bss节,这是为未初始化的数据。 比静态字符串更有用。 我们将一个静态值(字母h)移到我的msg内存位置,但是您可以像这样轻松移动一个寄存器

 mov [msg], eax 

下一行是如此重要,但每个“你好的世界”的作者只是掩饰它。 该0xa是一个行终止符std out需要或它will_not显示您的值。 这让我疯狂了很长时间,试图弄清楚为什么我的东西不会打印出来。 你需要那个行结束符。 这也是为什么我们需要定义我们的变量来保存两个值而不是一个值。 我们需要存储该行终止符。

其余的很简单,把参数扔到堆栈上并调用内核。 现在你有一个真正的例子来说明如何从实际的可变数据位置打印一些任意的数据。 请享用!