0

I'm new to GCC development, so I'm having a problem with a simple C program using an i686 cross compiler to output a flat binary file. Here's the C program,

void printChar(void);
void main() {
  printChar();
L1:
     goto L1;
}
void printChar(void)
{
__asm__ (
    "movb $62, %al\n\t"   // '>'
    "mov $0x0e, %ah \n\t"   // video function 0Eh (print char)
    "mov $0x0007, %ebx \n\t"    // color
    "int $0x10\n\t"
        );
}

here's the script file commands,

i686-elf-gcc -c test.c  -o test.o  -ffreestanding  -Wall -Wextra
i686-elf-ld test.o  -o test.bin --oformat binary --entry main

here's the debug listing,

0100 55            PUSH    BP
0101 89E5          MOV     BP,SP
0103 83E4F0        AND     SP,-10
0106 E80200        CALL    010B
0109 0000          ADD     [BX+SI],AL
010B EBFE          JMP     010B
010D 55            PUSH    BP
010E 89E5          MOV     BP,SP
0110 B03E          MOV     AL,3E
0112 B40E          MOV     AH,0E
0114 BB0700        MOV     BX,0007
0117 0000          ADD     [BX+SI],AL
0119 CD10          INT     10
011B 5D            POP     BP
011C C3            RET
011D 0000          ADD     [BX+SI],AL
011F 0014          ADD     [SI],DL

The call statement at 106 is calling an address 2 bytes short (10B) of the address it should be calling (10D). There's probably some simple alignment directive I should be using somewhere, but I can't find it. Any help is appreciated. Thanks..

Barmar
  • 741,623
  • 53
  • 500
  • 612
cc821
  • 1
  • 1
  • 1
    Your inline-assembly is 32-bit, your generated assembly is 16-bit. What. – EOF Nov 09 '15 at 23:12
  • 3
    The debug listing is incorrect, it's disassembling in 16 bit mode. Try to disassemble in 32 bit mode to get correct disassembly. – fuz Nov 09 '15 at 23:21
  • Also, what is your question? – fuz Nov 09 '15 at 23:21
  • The debug listing is the actual code put out by the linker in the test.bin output file. The dos debug program loads the binary file at address 100, thats the disassembled code starting from the beginning of the binary file test.bin. This is the correct info. The question is "why is the call statement jumping to the wrong address?". I run the test.bin file on a 386 machine. It doesn't work the way it is, but if I manually modify the call address to 10D, it works fine. – cc821 Nov 09 '15 at 23:40
  • GCC generates 32-bit code, and so generates a 32-bit CALL instruction with a 32-bit relative offset. If you try disassemble it as 16-bit code it won't disassemble correctly. In addition to the target address being wrong, there's an `ADD [BX+SI],AL` instruction that shouldn't be there. This is actually the upper 16 bits of the 32-bit relative offset. – Ross Ridge Nov 10 '15 at 02:04
  • Yes, everyone's right. When I use the nasm disassembler 'ndisasm' in the 32 bit mode, the results show the call to the right address. Now I have another problem, how do I get gcc to output 16 bit code for a PC boot program?? I tried the -m16 option but it doesn't seem to work. I also put '__asm__(".code16gcc\n\t");' in the C source code but that doesn't work either. I'm using V 4.9.3. – cc821 Nov 10 '15 at 17:43
  • Don't, Don't, Don't. It is possible to add `asm(".code16gcc")` but this is very bad. It doesn't exactly generate true 16-bit code. They use an operand size prefix, so don't expect it to work on a real 8086/8088 or an emulator that doesn't handle the prefixes introduced on the 386. The absolute best way is to write the boot program in assembler. you can have that code change to 32-bit protected mode and then call into _C_ (like a _main_ function) to continue processing. – Michael Petch Nov 10 '15 at 17:59
  • If you are willing to use something like GRUB (a mulitboot compliant boot loader), most of the drudgery is taken care of as it will place the system into protected mode, can use ELF32 binaries, and requires very little assembler code to get going. I wrote this [SO Answer](http://stackoverflow.com/questions/33488194/creating-a-simple-multiboot-kernel-loaded-with-grub2) for a different question about mulitboot loaders that may be of some value/interest. – Michael Petch Nov 10 '15 at 18:06
  • Thanks so much for your answer. Right now, I have a floppy disk boot loader which loads a flat binary file on the floppy into memory at address 0x1000 (this can be changed), then jumps to it. But the processor is still in real mode. So as you suggested, I have to change to 32-bit protected mode and then call into C (like a main function) to continue processing. By any chance do you have any example asm code that goes into protected mode? Then I can load a flat binary code file produced by gcc, jump to the start address, and the program should run in protected mode. – cc821 Nov 10 '15 at 19:43

0 Answers0