x86程序集:mul后打印整数到控制台(seg fault)

时间:2012-06-29 04:39:13

标签: x86 stdout nasm sys dword

我正在尝试学习x86程序集。我正在使用的书是Assembly Language - Step by Step, Programming With Linux(我必须说它非常好)。到目前为止我学到了很多,但我觉得我也应该挑战自己,在很多方面保持领先,这样我就可以通过做更快的学习(我可以跟随,自上而下的学习,但我发现它很乏味慢)。

所以,我认为尝试将两个寄存器(32位)相乘然后将数据输出到控制台是一个很酷的主意。

问题在于,当我执行程序时(我正在使用NASM,就像本书一样 - 虽然没有Insight调试器),但是我收到了一个分段错误。我已经在 gdb 中完成了相当多的调试,但是无论出于何种原因,我似乎无法弄清楚问题是什么。

我想知道为什么我会收到分段错误,这是一个多么好的方法 谴责这个问题。另外,如果我在代码中提出的评论与目前的评论不符,我将不胜感激,如果有人能够纠正我的话。

到目前为止,这是我的代码(评论很好)

感谢。

teh codez

section .data
;TODO

section .bss
valueToPrint: resb 4            ;alloc 4 bytes of data in 'valueToPrint'

section .text

global _start

_mul:
    mov eax, 0x2A ;store 42 in eax
    mov edx, 0x2A ;store 42 in edx
    mul eax
    ret

_safe_exit:
    mov eax, 1  ;initiate 'exit' syscall
    mov ebx, 0  ;exit with error code 0
    int 0x80    ;invoke kernel to do its bidding 

_start:
    nop                         ;used to keep gdb from complaining

    call _mul                       ;multiply the values
    mov [valueToPrint], eax         ;store address of eax in the contents of valueToPrint
    mov eax, 4                      ;specify a system write call - aka syswrite
    mov ebx, 1                      ;direction used to make the syswrite call output to console - i.e. stdout
    mov dword [ecx], valueToPrint   ;store valueToPrint in ecx: ecx represents the syswrite register
    int 0x80                        ;invoke kernel based on the given parameters

    call _safe_exit

修改

此外,我正在运行Arch Linux,如果这有所不同。

2 个答案:

答案 0 :(得分:3)

此行导致分段错误:

mov dword [ecx], valueToPrint

您告诉它将valueToPrint存储在地址ecx的内存位置。你永远不会初始化ecx(内核可能在程序启动时将它初始化为0),所以当你取消引用它时,你将访问一个无效的内存位置。

write(2)系统调用需要3个参数:寄存器ebx中的文件描述符编号,指向要写入ecx的字符串的指针,以及要写入的字节数{ {1}}。因此,如果您只想打印结果的原始二进制数据,您可以传递edx的地址,并告诉它从该地址打印4个字节。在这种情况下,valueToPrint为1764(十六进制为0x6e4),因此此代码将在x86上打印出4个字节valueToPrint,这是小端:

e4 06 00 00

答案 1 :(得分:1)

EDITIT! (忘了一个cmp!)

以基数10输出值...

; assuming value is in EAX (only)
.loop1:
    div   10      ; divide by 10, leave result in eax, REMAINDER in edx
    push  eax     ; save value
    mov   eax,edx
    or    eax,0x30 ; convert 0-9 to '0'-'9' (ascii 0x30='0')
    call  display_a_char ; (you write this!)
    pop   eax
    or    eax,eax ; set flags (edit!)
    jnz   .loop1
; all done, maybe put a \n return or something here