0
#include <stdio.h>
extern char *printbin(unsigned char);

int main(void)
{
  unsigned int x;

  printf("enter the character's ascii value in hex: \n");
  scanf("%x",&x);
  printf("The binary format for character %c is %s\n", x,   printbin((unsigned char)x));
  return 0;
}

The above C function is calling the below assembly function to print the binary of the unsigned char input. Donibble is basically just supposed to bitshift 4 times and each time it will write the carry flag to str using 0x30/0x31 for 0 and 1. I'm trying to iterate through the string and replace each character in %esi, but for some reason there is a segmentation fault at isone. Am I going about this the wrong way? I'm not sure if I'm using the dereferencing correctly with esi. Another issue is the str variable is stored at 0x100d00 according to the symbol table, but when I check x/x 0x100d00 in gdb it shows bytes that are completely unrelated to the string I stored there. Overall I'm just lost, any help is appreciated.

.globl printbin      # receives a char from a C program, returns binary of it by bit shifting and writing each carry flag to a string

.data

str:
    .string "ninebytes" # 9 byte long string, 8 for 0,1 1 for space
.text
# frrst argument is char, returns char pointer(array)
printbin:

prologue:
    push %ebp
    movl %esp, %ebp
    push %esi
    push %ebx

input:
    movl 8(%ebp), %edx  # move unsigned char argument to dl(converted hex to decimal)   
    movl str, %esi      # keep pointer to str in %esi
    movl str, %eax      # keep first pointer of string in %eax to return
    call donibble       # call donibble twice
    movl $0x20, (%esi)
    inc %esi
    call donibble       

end:
    pop %ebx
    pop %esi
    movl %ebp, %esp
    pop %ebp
    ret

donibble:
    # stores bits in %dl register to a string where the starting pointer is in %esi

    push %ecx       # save previous ecx
    movl 0, %ecx        # count to 3
counter:
    cmp %ecx, 4     
    jl bitshift     # if ecx is less than 4 (bitshift 4 times)
    pop %ecx        # else end
    ret

bitshift:
    inc %ecx        # add one to ecx
    shl $1, %dl     # left shift dl
    je isone        # if carry flag is 1 write 1 to string
    jmp iszero      # if CF is 0 write 0 to string

isone:
    movl $0x31, (%esi)  # move 1 to string
    incl %esi       # next char
    jmp counter

iszero:
    movl $0x30, (%esi)  # move 0 to string
    incl %esi       # next char
    jmp counter

pneuc4353
  • 21
  • 2
  • `movl` is a 4-byte store. `movb` stores a byte. Also, `movl str, %esi` loads 4 bytes of string data, not the address, since you omitted a `$` in `$str`. Use a debugger to look at values in registers. Similarly, `movl 0, %ecx` is a load from absolute address `0`, the NULL pointer. – Peter Cordes May 17 '22 at 19:02
  • I'd suggest looking at compiler output for a C function that does this. You have multiple other bugs, like using `je` instead of `jc` to branch on CF. But you don't need to branch, just `setc %al` / `add $'0', %al` or something. – Peter Cordes May 17 '22 at 19:07
  • BTW, the fun way to do this is [How to create a byte out of 8 bool values (and vice versa)?](https://stackoverflow.com/q/8461126) which avoids looping over bits, converting multiple at once. [Convert 16 bits mask to 16 bytes mask](https://stackoverflow.com/q/67201469) uses SIMD for 32 bits -> 32 bytes of ASCII – Peter Cordes May 17 '22 at 19:51

0 Answers0