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
mixing c and assembly
RE:mixing c and assembly
/* 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
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
RE:mixing c and assembly
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
Maybe this will help
HuntrCkr
RE:mixing c and assembly
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
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
RE:mixing c and assembly
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
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
RE:mixing c and assembly
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.
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.