Page 1 of 1

Turbo C and Assembly Won't Work!

Posted: Wed Jan 24, 2007 10:59 pm
by pcmattman
Hello all!

With Turbo C I can compile and link my kernel into a 16-bit exe (which my OS supports). However, the system hangs on the entry point (NASM code):

Code: Select all

extern _main

section _TEXT code

..start:
	mov ax,0x9000               ; put stack at 0x98000
	mov ss,ax
	mov sp,0x8000

	mov ax,seg _main	; segment of _main
	mov es,ax		; => es
	call [es:_main]		; go there now

	hangloop:
	pause
	jmp $
The program hangs on the call to es:_main, but without this contol just falls through to the hang loop.

Also, any ASM function I try to call from within my code don't execute at all - they are pretty much just skipped over without executing instructions.

Posted: Thu Jan 25, 2007 4:51 am
by Combuster
i doubt the call [es:_main] is what you want:

this is assembled as:
make a call to the address in memory location main, using prefix ES

and executed as
target = memory(es * 16 + main)
push ip
mov ip, target

the architecture has no direct opcode for call es:_main (without [ ] ), so either:

- You use a direct far call and either force the same segment (or fix the instruction using self-modyfing code, yuck)
- You create a far pointer in memory and use call far [structure]
- You push everything into place and use RETF

Posted: Thu Jan 25, 2007 8:32 am
by bubach
Why would you need a entry point for a 16-bit EXE program? You'r probably wrecking the EXE header and/or confusing the EXE bootloader.

Posted: Thu Jan 25, 2007 8:55 pm
by pcmattman
I've since been able to boot into the kernel successfully - and use my assembly functions - but the new problem is how to get a byte argument from Turbo C? I look at the disassembly and there is nothing at all pushed onto the stack before my assembly functions run. Why is this happening?

Posted: Fri Jan 26, 2007 2:39 am
by AJ
Hi,

Is it possible to see the code for that part - I don't see any pushes in your code.

If you mean that you would like to pass an argument to '_main', you will need to manually push your arguments before caling it. I use GCC which pushes from right to left, but I guess all C compilers are the same in this respect :?:

If you are expecting arguments from a previous boot loader, you need to retrieve them *before* you move the stack pointer!

Cheers,
Adam

Posted: Fri Jan 26, 2007 3:42 am
by Solar
AJ wrote:I use GCC which pushes from right to left, but I guess all C compilers are the same in this respect :?:
They need not be. Obviously there is the convention to use whatever the system libraries expect, but since we're talking about OS development, calling conventions could be left-to-right, unpadded, register passing or whatever...

Posted: Fri Jan 26, 2007 9:09 pm
by pcmattman
Sorry, the code above is not the code I was referencing! I've looked at other code to be linked with 'tlink' and they all use the calling convention I would normally use. Here's my assembly:

Code: Select all

global _kputc

section _TEXT

_kputc:

	push bp
	mov bp,sp

	mov al,[ss:bp+4]		; first argument
	mov ah,0eh
	mov bx,07h
	int 10h
	
	pop bp

	xor ax,ax				; return 0
	retn
Called like so:

Code: Select all

extern kputc( char );
kputc( 'D' );
But I've solved it - the argument to kputc can't be 'char' - it must be 'int'.

Posted: Fri Jan 26, 2007 11:22 pm
by pcmattman
New problem: functions can only be called once before the linker doesn't work properly anymore!! It says 'fixup overflow' and none of my functions work anymore. Any ideas?