问题
I'm trying to learn x86 assembly. The book I'm using is Assembly Language - Step by Step, Programming With Linux
(and I'd have to say it's pretty good). I've learned a lot so far, but I feel as though I should also be challenging myself to stay ahead in many respects so I can learn faster through doing (I can do follow along, top-down learning, but I find it tediously slow).
So, I figured it would be a cool idea to try and multiply two registers (32-bit) and then output the data to the console.
The problem is that when I execute the program (I'm using NASM, just as the book does - no Insight debugger though), I receive a segmentation fault. I've done a fair amount of debugging in gdb with this little hammer out, but for whatever reason I can't seem to figure out what the issue is.
I'd like to know why I'm receiving a segmentation fault, and what a good way would be to reprimand the issue. Also, if the comments I've made in the code don't match up with what exactly is happening, I'd be grateful if anyone could correct me on that.
Here's my code so far (it's well commented)
Thanks.
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
Edit
Also, I'm running Arch Linux, if that makes a difference.
回答1:
This line is causing the segmentation fault:
mov dword [ecx], valueToPrint
You're telling it to store valueToPrint
in the memory location at address ecx
. You never initialize ecx
(the kernel probably initializes it to 0 on program start for you), so when you dereference it, you're going to access an invalid memory location.
The write(2) system call takes 3 parameters: the file descriptor number in register ebx
, a pointer to the string to write in ecx
, and the number of bytes to write in edx
. So, if you want to just print the raw binary data of the result, you can pass the address of valueToPrint
, and tell it to print 4 bytes from that address. In this case, valueToPrint
is 1764 (0x6e4 in hex), so this code would print out the 4 bytes e4 06 00 00
on x86, which is little-endian:
mov [valueToPrint], eax ; store the result into memory
mov eax, 4 ; system call #4 = sys_write
mov ebx, 1 ; file descriptor 1 = stdout
mov ecx, valueToPrint ; store *address* of valueToPrint into ecx
mov edx, 4 ; write out 4 bytes of data
int 0x80 ; syscall
回答2:
EDITIT! (forgot a cmp!)
To output value in base 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
来源:https://stackoverflow.com/questions/11256143/x86-assembly-printing-integer-to-the-console-after-mul-seg-fault