Reputation: 11
Code:
;The value you want to print must be in the eax register
;one 32-byte resb to hold bit value
;and must be newline db
printDD_start:
push ebx
push ecx
push edx
push esi
push esp
mov esi,0
printDD:
cmp esi,31
jg printDD_printStart
test eax,1
jz printDD_zero
jmp printDD_one
printDD_zero:
mov dword [printDD_var_save + esi],48
inc esi
shr eax,1
jmp printDD
printDD_one:
mov dword [printDD_var_save + esi],49
inc esi
shr eax,1
jmp printDD
printDD_printStart:
mov esi,31
printDD_print:
cmp esi,0
jl printDD_exit
mov esp,printDD_var_save
add esp,esi
mov eax,4
mov ebx,1
mov ecx,esp
mov edx,1
int 80h
dec esi
jmp printDD_print
printDD_exit:
mov eax,4
mov ebx,1
mov ecx,newline
mov edx,1
int 80h
pop ebx
pop ecx
pop edx
pop esi
pop esp
ret
I'm printing the bits of a 4-byte variable to the screen. The program is running. It prints the value in the EAX register correctly but I get the latest segmentation fault error.
Upvotes: 1
Views: 96
Reputation: 39166
push ebx push ecx push edx ... pop ebx pop ecx pop edx
The stack is a Last-In-First-Out structure (LIFO). The value that you pushed first must come off latest. I often tag these push
and pop
instructions expressly to more easily track errors:
push ebx ; (1)
push ecx ; (2)
push edx ; (3)
...
pop edx ; (3)
pop ecx ; (2)
pop ebx ; (1)
mov esp,printDD_var_save add esp,esi
You have chosen to calculate the address for the character in the ESP
register. Not only is this very unusual, you don't need to use the extra register since you're going to have to store this address in the ECX
register anyway. You can even do it in one instruction:
lea ecx, [printDD_var_save + esi]
mov dword [printDD_var_save + esi],48 mov dword [printDD_var_save + esi],49
The character is a byte. Better then also write it as a byte:
mov byte [printDD_var_save + esi], 48
mov byte [printDD_var_save + esi], 49
You can simplify the task of converting the bits of EAX
into characters "0" or "1". The below suggested solution shifts out the bits one by one and adds the value from the carry flag (which represents the shifted out bit) to the ASCII code of the "0" character. The result of the adc dl, 0
will therefore be either the character "0" or the character "1".
You can also optimize your loops with fewer jumps. Because you already know that these loops will run at least once, you can omit the test at the top of the loop and only have a suitable test near the bottom of the loop where you will be jumping back conditionally.
printDD_start:
push ebx
push ecx
push edx
push esi
xor esi, esi ; Better than `mov esi, 0`
printDD:
mov dl, 48 ; You can replace the 48 by "0"
shr eax, 1
adc dl, 0 ; -> DL = {"0","1"}
mov [printDD_var_save + esi], dl
inc esi
cmp esi, 32
jb printDD
dec esi ; 32 - 1 = 31
printDD_print:
mov eax, 4
mov ebx, 1
lea ecx, [printDD_var_save + esi]
mov edx, 1
int 80h
dec esi ; Until ESI == -1
jns printDD_print
printDD_exit:
mov eax, 4
mov ebx, 1
mov ecx, newline
mov edx, 1
int 80h
pop esi
pop edx
pop ecx
pop ebx
ret
I don't expect the new code to segfault any more...
Upvotes: 2