c - Bootloader - Display String Runtime Error -
i going write first "hello world" bootloader program.i found article on codeproject website.here link of it. http://www.codeproject.com/articles/664165/writing-a-boot-loader-in-assembly-and-c-part up-to assembly level programming going well, when wrote program using c,same given in article, faced runtime error. code written in .c
file below.
__asm__(".code16\n"); __asm__("jmpl $0x0000,$main\n"); void printstring(const char* pstr) { while(*pstr) { __asm__ __volatile__("int $0x10": :"a"(0x0e00|*pstr),"b"(0x0007)); ++pstr; } } void main() { printstring("akatsuki9"); }
i created image file floppy.img
, checking output using bochs
. displaying
booting floppy... s
it should akatsuki9
. don't know did mistake? can 1 me find why facing runtime error?
brief answer: problem gcc (in fact, specific application of generated code) , not c program itself. it's hidden in assembly code.
long answer: longer (more elaborate) explanation specific details of problem:
(it helpful have assembly code. can obtained using -s switch of gcc or use 1 got gcc; i've attached @ end). if don't know opcode-prefixing, c-parameter passing in assembly, etc. have @ following background information section. looking @ assembly source, it's evident it's 32bit code. gcc '.code16' produces 16bit code 32bit-mode processor (using operand-size prefixes). when same exact code run in real (i.e. 16bit) mode, treated 32bit code. not issue (80386 , later processors can execute such, previous processors ignore operand-size prefix). problem occurs because gcc calculates offsets based on 32bit-mode of (processor) operation, not true (by default) when executing boot-code.
some background information (experienced assembly language programmers should skip this):
1. operand-size prefix: in x86, prefix bytes (0x66, 0x67, etc.) used obtain variants of instruction. 0x66 operand-size prefix obtain instruction non-default operand size; gas uses technique produce code '.code16'. example, in real (i.e. 16bit) mode, 89 d8
corresponds movw %bx,%ax
while 66 89 d8
corresponds movl %ebx,%eax
. relationship gets reversed in 32bit mode.
2. parameter passing in c: parameters passed on stack , accessed through ebp register.
3. call instruction: call branching operation next instruction's address saved on stack (for resuming). near call saves ip (when in 16bit mode) or eip ( when in 32bit mode). far call saves cs (code-segment register) along ip/eip.
4. push operation: saves value on stack. size of object subtracted esp.
exact problem
start @movl %esp, %ebp
in main: {{ %ebp set equal %esp }} pushl $.lc0
subtracts 4 stack pointer {{ .lc0 addresses char* "akatsuki9"; getting saved on stack (to accessed printstring function) }}call printstring
subtracts 2 stack pointer (16bit mode; ip 2bytes) pushl %ebp
in printstring: {{ 4 subtracted %esp }}movl %esp, %ebp
{{ %ebp , %esp @ 2+4(=6) bytes char *pstr }}pushl %ebx
changes %esp not %ebp movl 8(%ebp), %edx
{{ accessing 'pstr' @ %ebp+8 ??? }} accessing 'pstr' @ %ebp+8 instead of %ebp+6 (gcc had calculated offset of 8, assuming 32bit eip); program has obtained invalid pointer , it's going cause problem when program dereferences later: movsbl (%edx), %eax
.
fix
as of don't know of fix work gcc. writing boot-sector code, native 16bit code-generator, think, more effective (size-limit & other quirks explained above). if insist on using gcc generates code 32bit mode, fix avoid passing function parameters. more information, refer gcc , gas manuals. , please let me know if there workaround or option works gcc.
edit
i have found fix program make work desired purpose while still using gcc. kinda hackish & not-recommended. why post then? well, sort of proof of concept. here is: (just replace printstring function one)
void printstring(const char* pstr) { const char *hackptr = *(const char**)((char *)&pstr-2); while(*hackptr) { __asm__ __volatile__("int $0x10": :"a"(0x0e00|*hackptr),"b"(0x0007)); ++hackptr; } }
i invite @akatsuki , others (interested) verify works. above answer , added c-pointer arithmetic, can see why should.
my assembly-source file
.file "bootl.c" #app .code16 jmpl $0x0000,$main #no_app .text .globl printstring .type printstring, @function printstring: .lfb0: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 pushl %ebx .cfi_offset 3, -12 movl 8(%ebp), %edx movl $7, %ebx .l2: movsbl (%edx), %eax testb %al, %al je .l6 orb $14, %ah #app # 8 "bootl.c" 1 int $0x10 # 0 "" 2 #no_app incl %edx jmp .l2 .l6: popl %ebx .cfi_restore 3 popl %ebp .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .lfe0: .size printstring, .-printstring .section .rodata.str1.1,"ams",@progbits,1 .lc0: .string "akatsuki9" .section .text.startup,"ax",@progbits .globl main .type main, @function main: .lfb1: .cfi_startproc pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 pushl $.lc0 call printstring popl %eax leave .cfi_restore 5 .cfi_def_cfa 4, 4 ret .cfi_endproc .lfe1: .size main, .-main .ident "gcc: (ubuntu 4.8.2-19ubuntu1) 4.8.2" .section .note.gnu-stack,"",@progbits
Comments
Post a Comment