首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >汇编中的0-9打印

汇编中的0-9打印
EN

Stack Overflow用户
提问于 2016-02-23 02:48:58
回答 1查看 2.2K关注 0票数 0

我是这门语言的完全新手,我正在努力学习它。

这是我第一次处理低级语言。

这是我的不完整代码:

代码语言:javascript
复制
;------------Block 1----------
.386
.model flat,stdcall
option casemap:none


;------------Block 2----------
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib


;------------block 3----------
.data
first DW 1 ; increment this value


;------------Block 4----------
.data?
retvalue dd ?


;------------Block 5----------
.code
start:
mov ecx,10
mov eax, '1'

l1:
    nop  ;Add code here
loop l1



xor eax,eax
invoke ExitProcess,eax        
end start

它的64位架构与英特尔处理器。

我提到了这些文章,但它们似乎都不适合我的代码架构。

我已经烦了4个小时了。

任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-02-23 05:02:31

大会可以是一个交朋友的挑战。主要是因为给您提供了非常基本的可以使用的构建块、内存段、要使用的段中的地址、处理器寄存器将值加载到基本系统调用并从中获得结果,以及调用这些系统调用以对当前处理器寄存器中的值进行操作的方法。剩下的就由你来做了。我将尝试给您一个大致的概述,您可以在下面处理基本程序集调用时使用这个思想过程。

有许多网站文章提供了一个小的拼图,但很少有提供一个相当完整的语言概述。这就是我在评论中提到The Art of Assembly Language Programming的原因,我将在这里再次提到它。如果您花时间浏览这些部分,您将很好地掌握如何使用程序集。

在装配中,通常有几种方法来解决任何问题。打印0-9没有什么不同。在我的注释中,我解释了0-9的数值与可打印的ASCII字符'0'-'9'之间的区别。为了将值输出到屏幕,必须将ASCII值写入stdout (或文件描述符号1,其中stdin - 0stdout - 1stderr - 2)。

要将值写入stdout,必须使用适当的处理器寄存器中的适当值进行适当的sys_write系统调用。(您可以在unistd_32.h (32位)或unistd_64.h (64位)中找到适当的系统调用,它们位于您的发行版依赖的包含目录中,通常是/usr/include/asm/usr/include/asm-x86),您只需要担心2满足您的需要,sys_write (number 4)和sys_exit (number 1)。

什么进入什么处理器寄存器?您知道syscall号码将在第一个寄存器eax中。谢天谢地,您通常可以从C man page中找出所讨论的命令的其余部分。对于编写man 2 write page会有帮助(您可以以类似的方式对所有系统功能使用手册页)。查看write函数声明。注册值通常是函数所需的参数(按顺序排列)。例如:

代码语言:javascript
复制
ssize_t write(int fd, const void *buf, size_t count);
                  |               |           |
register:        ebx             ecx         edx

现在您知道了在每个寄存器中如何将一个字符写入stdout (文件描述符号),要执行写,需要生成一个内核中断来执行。(对于x86,这是int 80h)。看看如何将一个字符写入stdout

代码语言:javascript
复制
mov     eax, 4          ; linux (sys_write) in eax
mov     ebx, 1          ; fileno in ebx (stdout)
mov     ecx, achar      ; move achar address to ecx
mov     edx, 1          ; num chars to write in edx
int     0x80            ; kernel interrupt

(其中achar是要写入的字符的内存地址)

正如注释中所讨论的,您可以从数字0-9开始,并将'0'添加到值中以获得ASCII字符值(也可以简单地使用'0'or值以完成相同的任务)。您也可以从ASCII值'0'开始,打印它,通过1增加它的值(获取'1'等等)。总共做了10次。(于是想到了一个循环)

我将让您进一步了解程序集中的循环,但是基本方案是将循环计数(在您的例子中是10)加载到ecx中,然后跳转(jmp) (或loop)到循环的开始标签(例如next:looplbl:),然后每次在ecx中减少值,直到您到达0为止。

当循环完成后,然后将程序的退出值加载到ebx中,将sys_exit加载到eax中,然后调用内核中断退出。现在,在这个过程中有许多附加的子问题基础。这只是对一种解决方案方法的概述。您将只需阅读和调查其余的,因为它是远远超过可以塞进这篇文章。

若要提供帮助,请参阅以下示例。它只需从结束的ASCII值'0'中减去起始的ASCII值'9' (然后将1添加到总共10个字符,并使用该值作为循环计数)。然后循环10次,首先打印'0',然后将1添加到以前打印的值中,每次遍历循环,直到所有'0'-'9'都被打印出来。然后,它会打印一个newline,这样就不会用提示符和出口在同一行中塞入数字:

代码语言:javascript
复制
section .data
    achar db '0'
    nwln db 0xa
section .text

        global _start               ; must be declared for using gcc
    _start:                         ; tell linker entry point
            xor     eax, eax        ; zero eax register
            mov     al, byte '9'    ; move byte '9` (57) to al
            sub     al, byte '0'    ; subtract byte '0' (48) from al
            inc     al              ; add 1 to al (for total chars)
            xor     ecx, ecx        ; zero exc
            mov     cx, ax          ; move result to cx (loop count)
    next:
            push    ecx             ; save value of ecx on stack
            mov     eax, 4          ; linux (sys_write) in eax
            mov     ebx, 1          ; fileno in ebx (stdout)
            mov     ecx, achar      ; move achar address to ecx
            mov     edx, 1          ; num chars to write in edx
            int     0x80            ; kernel interrupt

            pop     ecx             ; restore loop count
            mov     dx, [achar]     ; move value of achar to dx
            inc     byte [achar]    ; increment value of achar (next char)
            loop    next            ; jump to next:

            mov     eax, 4          ; linux (sys_write) in eax
            mov     ebx, 1          ; fileno in ebx (stdout)
            mov     ecx, nwln       ; move nwln (newline) to ecx
            mov     edx, 1          ; num chars to write in edx
            int     0x80            ; kernel interrupt

            xor     ebx, ebx        ; zero ebx (for exit code 0)
            mov     eax, 1          ; system call number (sys_exit)
            int 0x80                ; kernel interrupt

(注意:通过在上面的代码中用'~'代替'9',可以输出ASCII字符集中的所有可打印字符)

Compile/Link

这是一个使用nasm汇编程序的编译/链接示例。如果你使用的是筋膜,或者是“雅玛斯”,它将是相似的。为了减少杂乱,我将所有的目标文件写入obj子and,将二进制文件写入bin子and。

代码语言:javascript
复制
nasm -f elf -o obj/prn_digits_32.o prn_digits_32.asm
ld -m elf_i386 -o bin/prn_digits_32 obj/prn_digits_32.o

输出

代码语言:javascript
复制
$ ./bin/prn_digits_32
0123456789

我希望这能帮到你。如果你有问题请告诉我。大概还有20种方法可以做到这点,有些我相信会更好。但这实际上只是一步一步关注内存中的每个寄存器和字节所做的事情。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35567881

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档