mixing c and assembly

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Michael Morrison

mixing c and assembly

Post by Michael Morrison »

I am trying to create a small bootsector using assembly language and C.  I am working with the
NASM assembler on Red Hat Linux 7.2.  I would like the boot sector to print the message 'Hi' to the
screen. Here is what my code looks like:

/*  HELLO.C  */
char H = 'H';
char I = 'i';

/*  HELLO.S  */
[SECTION .data]
extern  H
extern  I

[SECTION .text]
[GLOBAL _start]
_start

jmp bootup

bootup:
mov ax, 0xb800
mov es,ax

mov al, BYTE [H]
mov byte[es:0x0f9c] ,al

mov al, BYTE [I]
mov byte[es:0x0f9e], al

pause:
jmp pause
ret

times 510-($-$$) db 0
dw 0xAA55



After I have created the two files above, I first compile the hello.c file with the following command:

cc -c hello.c

this command creates the file 'hello.o' in the current directory.  Next I assemble the hello. s file with
the following command:

nasm -f aout -o  hello_asm.o  hello.s

This command creates the file 'hello_asm.o' in the current directory.  Next I link the hello.o and
hello_asm.o  into a file called hello.bin with the following command:

ld -o hello.bin -oformat binary -Ttext=0x00 hello.o hello_asm.o

This command creates the file 'hello.bin' into the current directory.  Lastly, I copy the hello.bin binary
to the boot sector of a disk with the command:

dd if=hello.bin of=/dev/fd0 bs=512 count=1

When i reboot my system with the diskette in the disk drive I only get a blank screen. Can anyone
please help me with this problem.

Thanks
Michael Morrison
carbonBased

RE:mixing c and assembly

Post by carbonBased »

   /*  HELLO.C  */
   char H = 'H';
   char I = 'i';

That's gonna get pretty difficult withen strings longer than 2 characters... :)


   jmp bootup

   bootup:
   mov ax, 0xb800
   mov es,ax

What about ds?  You need to set your data segment, or else H and I will be offsets into the wrong segment.  Either jump to 0x07c0:bootup, or more 0x07c0 into ds... or add 0x7c00 to every offset, but that'd be quite a pain in the @$$ :)

The rest looks fine, though.  I would, however, keep everything with the same object format.  In other words, assembly your nasm code with -f elf, seeing as gcc produces elf code.

It may come back to haunt you otherwise.  A.OUT defines all C symbols prefixed with an underscore, whereas ELF doesn't.

Jeff
HuntrCkr

RE:mixing c and assembly

Post by HuntrCkr »

also, you specify 0x00 as you location for your code when you link... not sure if this is a problem if the cs and ds are set, but usually i specify 0x7c00 as the location

Maybe this will help
HuntrCkr
Michael Morrison

RE:mixing c and assembly

Post by Michael Morrison »

Thanks for all of your help guys it is greatly appreciated.  I do however have a few more questions
concerning c and assembly.    I made the suggested changes to my code to ensure that the ds register
referenced the correct segment.  The code I used follows:

[SECTION .data]
letter1 db 'P'
letter2 db 'K'

[SECTION .text]
[GLOBAL _start]
_start

jmp 0x07c0:bootup

bootup:
mov ax, cs
mov ds, ax
mov ax, 0xb800
mov es,ax

mov al, BYTE [letter1]
mov BYTE [es:0x0f9c], al

mov al, BYTE [letter2]
mov BYTE [es:0x0f9e], al

pause:
jmp pause
ret

times 510-($-$$) db 0
dw 0xAA55

I then compiled this code with the following command:

nasm -f bin hello.s -o hello.bin

when i placed this binary in the bootsector of  a floppy and rebooted my system, the letters 'PK' were
outputted to the screen.  So I knew that the ds register was properly setup.  

Next I tried the following code:

/* HELLO.C */

char H = 'H';
char I = 'i';


/* HELLO.S */

[SECTION .data]
extern  H
extern  I

[SECTION .text]
[GLOBAL _start]
_start

jmp 0x07c0:bootup

bootup:
mov ax, cs
mov ds, ax
mov ax, 0xb800
mov es,ax

mov al, BYTE [H]
mov BYTE [es:0x0f9c], al

mov al, BYTE [I]
mov BYTE [es:0x0f9e], al

pause:
jmp pause
ret

times 510-($-$$) db 0
dw 0xAA55

Then i ran the following commands:

cc -c hello.c
nasm -f elf -o  hello_asm.o  hello.s
ld -o hello.bin -oformat binary -Ttext=0x00 hello.o hello_asm.o
mount /mnt/floppy
dd if=hello.bin of=/dev/fd0 bs=512 count=1

However when i rebooted my system , i got a  blank screen. I don't know what i am doing wrong now.

Thank You
Michael Morrison  
carbonBased

RE:mixing c and assembly

Post by carbonBased »

You're linking in the wrong order!

How does ld know where your entry point is, in a binary executable?  It doesn't!  So, you've got to make sure that your entry point ends up being the first instruction executed... which means your assembly code should be linked in first.

The way you've got it, the C code is linked first... the C code just contains two declarations, and no code what-so-ever... you can't run "H"... can't run "I" either :)

Oh, and btw, you don't have to mount the floppy drive in order to dd to /dev/fd0...

Jeff
jcmatias

RE:mixing c and assembly

Post by jcmatias »

Your code is OK.
  You must remember that boot is a 16 bits process (real mode).  ld linker produces a 32 bits code. To run your code you must be in Protected Mode.
Post Reply