Page 1 of 1

How to use Open Watcom WLINK?

Posted: Mon Nov 28, 2011 5:01 am
by jona
Hi, I'm trying to create real-mode 16-bit code using Open Watcom 1.9, but I don't understand how linker work. Bootloader code will load a flat binary file in memory location 0000:8000H. This is my simple C code for the flat binary file:

Code: Select all

void print(char* text) {
  unsigned char* buffer = (unsigned char*) 0xb800;
  buffer[0] = text[0];
}
void KernelMain() {
  print("welcome");
  while(1);
}
I'm using the following command to compile it:

Code: Select all

$ watcom/binl/wcc -s -wx -d0 -fr -ms -zl -fo=main.o main.c
And then, using the following command to generate a flat binary file:

Code: Select all

$ watcom/binl/wlink FILE main.o NAME output.bin OUTPUT RAW OPTION NODEFAULTLIBS, START=KernelMain_
The generated file is something like this:

Code: Select all

$ hexdump -Cv output.bin
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000010  53 56 89 c3 be 00 b8 8a  1f 88 1c 5e 5b c3 b8 00  |SV.........^[...|
00000020  77 65 6c 63 6f 6d 65 00                                  |welcome.|
00000028
I don't know much how linker works. Why there are a lot of 00's in the beginning of the file? Can I remove them? How to tell linker to start writing from KernelMain() function, not from print() function? I want the first byte generated (offset 0) taken from KernelMain() functions machine code. Is that possible?

Re: How to use Open Watcom WLINK?

Posted: Mon Nov 28, 2011 11:47 am
by tom9876543
If you know your real mode code will be less than 64KB, would it be possible to simply compile to a COM file (with no stdlib / dos calls).

Re: How to use Open Watcom WLINK?

Posted: Mon Nov 28, 2011 12:21 pm
by Casm
jona wrote: I don't know much how linker works. Why there are a lot of 00's in the beginning of the file? Can I remove them?
There will probably be 8000H of them. You can write a utility to strip them off, and then any ferences in the file will begin with 8000h, and move on from there - which is probably what you want.

An alternative might be:

wlink [your_file_mame(s)] [other options] order clname code offset=0x8000 clname data

Assuming that you have a data section with a 'data' class. Otherwise leave that bit off.

Re: How to use Open Watcom WLINK?

Posted: Mon Nov 28, 2011 2:06 pm
by Tosi
First, I would recommend learning how the C language works, especially pointers:

Code: Select all

void print(char* text) {
  unsigned char* buffer = (unsigned char*) 0xb800;
  buffer[0] = text[0];
}
This only writes the first character of the string to the screen. It also doesn't set the attribute byte, which is probably not much of a problem since the screen should be cleared to some value by the BIOS.

You made other mistakes in your code. You don't specify that the code is loaded at 0000:8000, by way of ORG directive or command line parameter, so the compiler will probably assume 0000. In this case, you need to set the segment registers, which you don't do. I doubt the compiler will do it for you.

Second, did you read the linker documentation? I don't know much about OpenWatcom, but a quick google gave the homepage which seems to have tons of information about the compiler. It is your responsibility to understand your toolchain. It is also your responsibility to know how to look for information: you should at least look at the wiki, search the forum archives, use google, and look at the relevant documentation for your toolset before posting here.

Re: How to use Open Watcom WLINK?

Posted: Mon Nov 28, 2011 2:18 pm
by Combuster
Tosi wrote:First, I would recommend learning how the C language works, especially pointers:

Code: Select all

void print(char* text) {
  unsigned char* buffer = (unsigned char*) 0xb800;
  buffer[0] = text[0];
}
This only writes the first character of the string to the screen. It also doesn't set the attribute byte, which is probably not much of a problem since the screen should be cleared to some value by the BIOS.
It actually does not even write to the display, but rather data+0xb800, somewhere far from 0xb8000. You need some far pointer trick to point something there.

Re: How to use Open Watcom WLINK?

Posted: Mon Nov 28, 2011 8:09 pm
by jona
Thanks all for the helps. I've changed the C code into:

Code: Select all

extern void print(unsigned char __c);
#pragma aux print = \
  "mov ax, 0xb800" \
  "mov es, ax" \
  "mov byte ptr es:0, dl" \
  "mov dl, 0x7" \
  "mov byte ptr es:1, dl" \
  parm [dl] \
  modify [ax];

void KernelMain() {
  print('J');
}
And added one asm file that produces entry.o:

Code: Select all

.model small
.code ENTRY
extern KernelMain_ : proc
jmp KernelMain_
db 0x90
end
I'm executing WLINK like this:

Code: Select all

watcom/binl/wlink FILE entry.o FILE main.o NAME output.bin FORMAT DOS OUTPUT RAW 
  OFFSET=0x8000 OPTION NODEFAULTLIBS
  ORDER CLNAME CODE
      SEGMENT ENTRY OFFSET=0x8000
      SEGMENT main_TEXT OFFSET=0x8004

Re: How to use Open Watcom WLINK?

Posted: Tue Nov 29, 2011 3:06 am
by rdos
I generate all the boot-code (boot-sector, loader, GRUB stub) with OpenWatcom. I use only assembly in those files, but it would be possible to use C as well. I don't use the binary output option (mostly because it isn't supported in the IDE, and I don't want to use ordinary makefiles). Instead, I created new targets in the linker and IDE. You could use those, but they are not part of 1.9, rather are only present in trunk. Since nobody seemed to want those functions, I placed them in the RDOS kernel target group. They are called 16-bit binary, 32-bit binary and multiboot stub.