i am trying to build a program that would print a value of each bit in AL into the console, because i want to see the time (in seconds) stored in eax. GDB says my program has received signal SIGSEGV, which indicates segmentation fault.
I have realized now that i had used pop instruction in my loop and push instruction before the loop, which resaulted in segmentation fault.
I have fixed it simply by moving the data to edi.
But now my fixed program doesn't output anything to the console. It seems like it runs forever.
Does anyone have any idea why?
Thanks a lot! Feel free to ask me questions about my shitty code.
SECTION .data
linefeed db 0xA,0xD
SECTION .bss
SECTION .text
global _start
_start:
mov eax,13
int 80h
;push eax
mov edi,eax
mov bl,1
mov cl,0
bitmaska:
shl bl,cl
and al,bl
shr al,cl
shr bl,cl
add al,48
mov edx,1
movzx ecx,al
mov ebx,1
mov eax,4
int 80h
;pop eax
mov eax,edi
inc cl
cmp cl,8
jnz bitmaska
konec:
mov edx,1
mov ecx,linefeed
mov ebx,1
mov eax,4
int 80h
mov ebx,0
mov eax,1
int 80h
Express edit to address more issues from a comment. Currently my browser doesn't allow writing comments
mov eax,13 int 80h
There's trouble with that sys_time
that is supposed to return in EAX the time as the number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). You forgot to initialize the EBX argument. If EBX happened to be non-zero, then the service would have tried to additionally store the result in whatever memory EBX was pointing to. That's a good reason for a segmentation error! You should always zero the EBX register with this service:
xor ebx, ebx ; Don't need a copy in memory
mov eax, 13 ; sys_time
int 80h ; -> EAX
But, if you did want a copy in a memory location, then just reserve room for it. Preferrably in the .bss
section, but in the .data
section would be fine too. You create it with: MyCopyOfTheTime dd 0
when in the .data
section, or with MyCopyOfTheTime resd 1
when in the .bss
section.
The actual retrieval then requires EBX pointing to this doubleword:
mov ebx, MyCopyOfTheTime ; Want a copy in memory
mov eax, 13 ; sys_time
int 80h ; -> EAX
You can use this copy from memory with the usual instructions. You can read from it with eg. mov eax, [MyCopyOfTheTime]
, and you write to it with eg. mov dword [MyCopyOfTheTime], 0
.
The write
operation within the loop messes with the other registers that your loop depends on! Moreover you didn't supply in ECX an address for this system call. And once it will work, you will notice that the output is in the reverse order because you begin at the lowest bit. The binary representation must have the most significant bit on the left side, so start at the highest bit.
I would suggest that you don't output while being in the loop, but store to memory, and then in the end you can output everything in one go.
To this effect you change the linefeed definition to be:
buffer db '????????'
linefeed db 10
The 8 question marks are place-holders for your actual '0' and '1' characters. The final output then becomes:
konec:
mov edx, 9
mov ecx, buffer
mov ebx, 1
mov eax, 4
int 80h
Now the core loop should be a simple one. No need to shift that many times by CL:
mov ebx, eax
mov edi, buffer
mov ecx, 8
bitmaska:
mov al, 48
shl bl, 1 ; Shift a bit out into the carry
adc al, 0 ; Add that bit to the value 48
stosb ; Store '0' or '1' in the buffer
dec ecx
jnz bitmaska
If the reverse order was intentional, then just replace shl bl, 1
by shr bl, 1
.