Bootloader using mixed code using EXTERN - c

I am creating simple calculator application on bootloader using mixed code including C language with Assembly Code.
My C language Code is (addasm.c):
#include
int main() {
bootmain();
return 0 ;
}
int bootmain()
{
int arg1, arg2, add, sub, mul, quo, rem ;
printf( "Enter two integer numbers : " );
scanf( "%d%d", &arg1, &arg2 );
/* Perform Addition, Subtraction, Multiplication & Division */
__asm__ ( "addl %%ebx, %%eax;" : "=a" (add) : "a" (arg1) , "b" (arg2) );
__asm__ ( "subl %%ebx, %%eax;" : "=a" (sub) : "a" (arg1) , "b" (arg2) );
__asm__ ( "imull %%ebx, %%eax;" : "=a" (mul) : "a" (arg1) , "b" (arg2) );
__asm__ ( "movl $0x0, %%edx;"
"movl %2, %%eax;"
"movl %3, %%ebx;"
"idivl %%ebx;" : "=a" (quo), "=d" (rem) : "g" (arg1), "g" (arg2) );
printf( "%d + %d = %d\n", arg1, arg2, add );
printf( "%d - %d = %d\n", arg1, arg2, sub );
printf( "%d * %d = %d\n", arg1, arg2, mul );
printf( "%d / %d = %d\n", arg1, arg2, quo );
printf( "%d %% %d = %d\n", arg1, arg2, rem );
return 0;
}
I had created bootmain() function in C which i need to use in assembly code.
My assembly code (ccode.asm) is :
[BITS 16] ; 16 bit code generation
[ORG 0x7C00] ; ORGin location is 7C00
extern bootmain
;Main program
main: ; Main program label
call bootmain
; End matter
times 510-($-$$) db 0 ; Fill the rest of the sector with zeros
dw 0xAA55 ; Boot signature
Now i am compiling this
nasm -f elf -o main.o ccode.asm #assemble our asm file
But It gives me error for ORG keyword that it is undefined keyword.
If i will remove this keyword then it will give me errorless output.
After removing ORG keyword I am compiling like this way:
nasm -f elf -o main.o ccode.asm #assemble our asm file
gcc addasm.c main.o -o add_asm #compile and link in one step
./add_asm
So I am using this final add_asm file and make my usb drive bootable by puting this add_asm file using Disk Explorer.
But at booting it is showing message : Missing Operating System
So is this a problem of not using ORG in Assembly file.
This is mainly problem with ELF that i am using with NASM.But for external C function and for EXTERN keyword I need to use ELF.
The alternative code of ORG is :
[Bits 16]
extern bootmain
start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096
call bootmain
mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax
times 510-($-$$) db 0; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature
But it also does not work... It gives me same error as "Missing Operating System" at time of booting.
Is there any another way to include C function in assembly file (*.asm)?
I am stuck here. If there is any suggestion please give me.
Thank you.

You cannot turn a normal C program into a bootloader like that.
The environment in which a bootloader runs is significantly different from a normal executable. In particular, it does not include a C library that you can link against (or, for that matter, any linker at all!), so functions like printf() and scanf() are not available unless you link in appropriate versions, which you are not doing.
You are compiling your program as a 32-bit executable. An x86 system boots up in 16-bit mode. There is a significant amount of initialization which must take place to switch into that mode, none of which is present here.
You are compiling your program as a Linux ELF (or possibly Windows PE?) executable. This is not the correct format for a bootloader.

Related

Performing syscalls in inline C assembly causes a segfault

I recently dabbled into low level programming, and want to make a function somesyscall that accepts (CType rax, CType rbx, CType rcx, CType rdx). struct CType looks like:
/*
TYPES:
0 int
1 string
2 bool
*/
typedef struct {
void* val;
int typev;
} CType;
the function is a bit messy, but in theory should work:
#include <errno.h>
#include <stdbool.h>
#include "ctypes.h"
//define functions to set registers
#define seteax(val) asm("mov %0, %%rax" :: "g" (val) : "%rax")
#define setebx(val) asm("mov %0, %%rbx" :: "g" (val) : "%rbx")
#define setecx(val) asm("mov %0, %%rcx" :: "g" (val) : "%rcx")
#define setedx(val) asm("mov %0, %%rdx" :: "g" (val) : "%rdx")
///////////////////////////////////
#define setregister(value, register) \
switch (value.typev) { \
case 0: { \
register(*((double*)value.val)); \
break; \
} \
case 1: { \
register(*((char**)value.val)); \
break; \
} \
case 2: { \
register(*((bool*)value.val)); \
break; \
} \
}
static inline long int somesyscall(CType a0, CType a1, CType a2, CType a3) {
//set the registers
setregister(a0, seteax);
setregister(a1, setebx);
setregister(a2, setecx);
setregister(a3, setedx);
///////////////////
asm("int $0x80"); //interrupt
//fetch back the rax
long int raxret;
asm("mov %%rax, %0" : "=r" (raxret));
return raxret;
}
when I run with:
#include "syscall_unix.h"
int main() {
CType rax;
rax.val = 39;
rax.typev = 0;
CType rbx;
rbx.val = 0;
rbx.typev = 0;
CType rcx;
rcx.val = 0;
rcx.typev = 0;
CType rdx;
rdx.val = 0;
rdx.typev = 0;
printf("%ld", somesyscall(rax, rbx, rcx, rdx));
}
and compile (and run binary) with
clang test.c
./a.out
I get a segfault. However, everything seems to look correct. Am I doing anything wrong here?
After macro expansion you will have something like
long int raxret;
asm("mov %0, %%rax" :: "g" (a0) : "%rax");
asm("mov %0, %%rbx" :: "g" (a1) : "%rbx");
asm("mov %0, %%rcx" :: "g" (a2) : "%rcx");
asm("mov %0, %%rdx" :: "g" (a3) : "%rdx");
asm("int $0x80");
asm("mov %%rax, %0" : "=r" (raxret));
This doesn't work because you haven't told the compiler that it's not allowed to reuse rax, rbx, rcx, and rdx for something else during the sequence of asm statements. For instance, the register allocator might decide to copy a2 from the stack to rax and then use rax as the input operand for the mov %0, %%rcx instruction -- clobbering the value you put in rax.
(asm statements with no outputs are implicitly volatile so the first 5 can't reorder relative to each other, but the final one can move anywhere. For example, be moved after later code to where the compiler finds it convenient to generate raxret in a register of its choice. RAX might no longer have the system call return value at that point - you need to tell the compiler that the output comes from the asm statement that actually produces it, without assuming any registers survive between asm statements.)
There are two different ways to tell the compiler not to do that:
Put only the int instruction in an asm, and express all of the requirements for what goes in what register with constraint letters:
asm volatile ("int $0x80"
: "=a" (raxret) // outputs
: "a" (a0), "b" (a1), "c" (a2), "d" (a3) // pure inputs
: "memory", "r8", "r9", "r10", "r11" // clobbers
// 32-bit int 0x80 system calls in 64-bit code zero R8..R11
// for native "syscall", clobber "rcx", "r11".
);
This is possible for this simple example but not always possible in general, because there aren't constraint letters for every single register, especially not on CPUs other than x86.
// use the native 64-bit syscall ABI
// remove the r8..r11 clobbers for 32-bit mode
Put only the int instruction in an asm, and express the requirements for what goes in what register with explicit register variables:
register long rax asm("rax") = a0;
register long rbx asm("rbx") = a1;
register long rcx asm("rcx") = a2;
register long rdx asm("rdx") = r3;
// Note that int $0x80 only looks at the low 32 bits of input regs
// so `uint32_t` would be more appropriate than long
// but really you should just use "syscall" in 64-bit code.
asm volatile ("int $0x80"
: "+r" (rax) // read-write: in=call num, out=retval
: "r" (rbx), "r" (rcx), "r" (rdx) // read-only inputs
: "memory", "r8", "r9", "r10", "r11"
);
return rax;
This will work regardless of which registers you need to use. It's also probably more compatible with the macros you're trying to use to erase types.
Incidentally, if this is 64-bit x86/Linux then you should be using syscall rather than int $0x80, and the arguments belong in the ABI-standard incoming-argument registers (rdi, rsi, rdx, rcx, r8, r9 in that order), not in rbx, rcx, rdx etc. The system call number still goes in rax, though. (Use call numbers from #include <asm/unistd.h> or <sys/syscall.h>, which will be appropriate for the native ABI of the mode you're compiling for, another reason not to use int $0x80 in 64-bit mode.)
Also, the asm statement for the system-call instruction should have a "memory" clobber and be declared volatile; almost all system calls access memory somehow.
(As a micro-optimization, I suppose you could have a list of system calls that don't read memory, write memory, or modify the virtual address space, and avoid the memory clobber for them. It would be a pretty short list and I'm not sure it would be worth the trouble. Or use the syntax shown in How can I indicate that the memory *pointed* to by an inline ASM argument may be used? to tell GCC which memory might be read or written, instead of a "memory" clobber, if you write wrappers for specific syscalls.
Some of the no-pointer cases include getpid where it would be a lot faster to call into the VDSO to avoid a round trip to kernel mode and back, like glibc does for the appropriate syscalls. That also applies to clock_gettime which does take pointers.)
Incidentally, beware of the actual kernel interfaces not matching up with the interfaces presented by the C library's wrappers. This is generally documented in the NOTES section of the man page, e.g. for brk(2) and getpriority(2)

Intel asm syntax with GCC: undefined reference

I am running Ubuntu 64-bit and I have this code:
#include <stdio.h>
int main() {
int x, y;
int z = 0;
printf("Enter two numbers: ");
scanf("%d %d", &x, &y);
asm(".intel_syntax noprefix\n"
"MOV EAX, _x\n"
"MOV ECX, _y\n"
"ADD EAX, ECX\n"
"MOV _z, EAX\n"
".att_syntax\n");
printf("%d + %d = %d \n", x, y, z);
return 0;
}
According to lecture at school it should work, but when I try to compile it with GCC I get this error:
/tmp/ccU4vNLr.o: In function `main':
Jung_79913_211.c:(.text+0x4a): undefined reference to `_x'
Jung_79913_211.c:(.text+0x51): undefined reference to `_y'
Jung_79913_211.c:(.text+0x5a): undefined reference to `_z'
collect2: error: ld returned 1 exit status
I know GCC uses AT&T asm syntax by default, but I need Intel systax at university. So question is, how I can get it working?
Two things: First, on Linux you don't prefix C symbols with an underscore in assembly, so x, y, z instead of _x, _y, _z. Second, these three variables are automatic variables. You cannot refer to automatic variables like this as no symbols are created for them. Instead, you need to tell the compiler to hand-over these variables into your assembly. You also need to mark the registers eax and ecx as clobbered because your assembly modifies them. Read this documentation for details. Here is how this could work with your code:
asm(
"MOV EAX, %1\n"
"MOV ECX, %2\n"
"ADD EAX, ECX\n"
"MOV %0, EAX\n"
: "=r" (z) : "r" (x), "r" (y) : "eax", "ecx");
You also need to compile with -masm=intel for this to work as otherwise gcc will insert references to registers in AT&T syntax, causing a compilation error. Even better, learn AT&T syntax if you plan to write a lot of inline assembly for gcc.

What ensures reads/writes of operands occurs at desired timed with extended ASM?

According to GCC's Extended ASM and Assembler Template, to keep instructions consecutive, they must be in the same ASM block. I'm having trouble understanding what provides the scheduling or timings of reads and writes to the operands in a block with multiple statements.
As an example, EBX or RBX needs to be preserved when using CPUID because, according to the ABI, the caller owns it. There are some open questions with respect to the use of EBX and RBX, so we want to preserve it unconditionally (its a requirement). So three instructions need to be encoded into a single ASM block to ensure the consecutive-ness of the instructions (re: the assembler template discussed in the first paragraph):
unsigned int __FUNC = 1, __SUBFUNC = 0;
unsigned int __EAX, __EBX, __ECX, __EDX;
__asm__ __volatile__ (
"push %ebx;"
"cpuid;"
"pop %ebx"
: "=a"(__EAX), "=b"(__EBX), "=c"(__ECX), "=d"(__EDX)
: "a"(__FUNC), "c"(__SUBFUNC)
);
If the expression representing the operands is interpreted at the wrong point in time, then __EBX will be the saved EBX (and not the CPUID's EBX), which will likely be a pointer to the Global Offset Table (GOT) if PIC is enabled.
Where, exactly, does the expression specify that the store of CPUID's %EBX into __EBX should happen (1) after the PUSH %EBX; (2) after the CPUID; but (3) before the POP %EBX?
In your question you present some code that does a push and pop of ebx. The idea of saving ebx in the event that you compile with gcc using -fPIC (position independent code) is correct. It is up to our function not to clobber ebx upon return in that situation. Unfortunately the way you have defined the constraints you explicitly use ebx. Generally the compiler will warn you (error: inconsistent operand constraints in an 'asm') if you are using PIC code and you specify =b as an output constraint. Why it doesn't produce a warning for you is unusual.
To get around this problem you can let the assembler template choose a register for you. Instead of pushing and popping we simply exchange %ebx with an unused register chosen by the compiler and restore it by exchanging it back after. Since we don't wish to have the compiler clobber our input registers during the exchange we specify early clobber modifier, thus ending up with a constraint of =&r (instead of =b in the OPs code). More on modifiers can be found here. Your code (for 32 bit) would look something like:
unsigned int __FUNC = 1, __SUBFUNC = 0;
unsigned int __EAX, __EBX, __ECX, __EDX;
__asm__ __volatile__ (
"xchgl\t%%ebx, %k1\n\t" \
"cpuid\n\t" \
"xchgl\t%%ebx, %k1\n\t"
: "=a"(__EAX), "=&r"(__EBX), "=c"(__ECX), "=d"(__EDX)
: "a"(__FUNC), "c"(__SUBFUNC));
If you intend to compile for X86_64 (64 bit) you'll need to save the entire contents of %rbx. The code above will not quite work. You'd have to use something like:
uint32_t __FUNC = 1, __SUBFUNC = 0;
uint32_t __EAX, __ECX, __EDX;
uint64_t __BX; /* Big enough to hold a 64 bit value */
__asm__ __volatile__ (
"xchgq\t%%rbx, %q1\n\t" \
"cpuid\n\t" \
"xchgq\t%%rbx, %q1\n\t"
: "=a"(__EAX), "=&r"(__BX), "=c"(__ECX), "=d"(__EDX)
: "a"(__FUNC), "c"(__SUBFUNC));
You could code this up using conditional compilation to deal with both X86_64 and i386:
uint32_t __FUNC = 1, __SUBFUNC = 0;
uint32_t __EAX, __ECX, __EDX;
uint64_t __BX; /* Big enough to hold a 64 bit value */
#if defined(__i386__)
__asm__ __volatile__ (
"xchgl\t%%ebx, %k1\n\t" \
"cpuid\n\t" \
"xchgl\t%%ebx, %k1\n\t"
: "=a"(__EAX), "=&r"(__BX), "=c"(__ECX), "=d"(__EDX)
: "a"(__FUNC), "c"(__SUBFUNC));
#elif defined(__x86_64__)
__asm__ __volatile__ (
"xchgq\t%%rbx, %q1\n\t" \
"cpuid\n\t" \
"xchgq\t%%rbx, %q1\n\t"
: "=a"(__EAX), "=&r"(__BX), "=c"(__ECX), "=d"(__EDX)
: "a"(__FUNC), "c"(__SUBFUNC));
#else
#error "Unknown architecture."
#endif
GCC has a __cpuid macro defined in cpuid.h. It defined the macro so that it only saves the ebx and rbx register when required. You can find the GCC 4.8.1 macro definition here to get an idea of how they handle cpuid in cpuid.h.
The astute reader may ask the question - what stops the compiler from choosing ebx or rbx as the scratch register to use for the exchange. The compiler knows about ebx and rbx in the context of PIC, and will not allow it to be used as a scratch register. This is based on my personal observations over the years and reviewing the assembler (.s) files generated from C code. I can't say for certain how more ancient versions of gcc handled it so it could be a problem.
I think you understand, but to be clear, the "consecutive" rule means that this:
asm ("a");
asm ("b");
asm ("c");
... might get other instructions interposed, so if that's not desirable then it must be rewritten like this:
asm ("a\n"
"b\n"
"c");
... and now it will be inserted as a whole.
As for the cpuid snippet, we have two problems:
The cpuid instruction will overwrite ebx, and hence clobber the data that PIC code must keep there.
We want to extract the value that cpuid places in ebx while never returning to compiled code with the "wrong" ebx value.
One possible solution would be this:
unsigned int __FUNC = 1, __SUBFUNC = 0;
unsigned int __EAX, __EBX, __ECX, __EDX;
__asm__ __volatile__ (
"push %ebx;"
"cpuid;"
"mov %ebx, %ecx"
"pop %ebx"
: "=c"(__EBX)
: "a"(__FUNC), "c"(__SUBFUNC)
: "eax", "edx"
);
__asm__ __volatile__ (
"push %ebx;"
"cpuid;"
"pop %ebx"
: "=a"(__EAX), "=c"(__ECX), "=d"(__EDX)
: "a"(__FUNC), "c"(__SUBFUNC)
);
There's no need to mark ebx as clobbered as you're putting it back how you found it.
(I don't do much Intel programming, so I may have some of the assembler-specific details off there, but this is how asm works.)

Inline ASM in C, compiled with MinGW/GCC using "-masm=intel": "undefined reference"

I've been looking around a lot for examples of using inline ASM and I've seen seen a few different approaches.
I've gone with the -masm=intel option when compiling. As I understand it, when using this option you can just write the inline ASM as you would with intel syntax.
I have also seen approaches where people use ".intel_syntax"
When I compile I get the following message.
i586-mingw32msvc-gcc -masm=intel -o KDOS.exe KDOS.c
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x5f): undefined reference to `address'
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x6a): undefined reference to `ipAddr'
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x79): undefined reference to `csAddr'
/tmp/ccVIXhRF.o:KDOS.c:(.text+0x11d): undefined reference to `address'
collect2: ld returned 1 exit status
I've looked around for a solution but I can't seem to find one. I've seen threads saying you can't pass C variables into inline ASM, but I've also seen some stuff saying there are workarounds. They didn't quite apply to what I was doing though so I wasn't really sure what to make of them. Sorry if it is an obvious answer but this is my first time using inline ASM much less fooling around with converting the syntax.
Here is my code. I am working through a book and this is some sample code within it. It was not compiled with gcc in the book so this is why I need to convert to intel syntax, because I need it to run on windows obviously. This is my modified version of the code:
// KDOS.c
// Chapter 2
#include<stdio.h>
#define WORD unsigned short
#define IDT_001_ADDR 0 //start address of first IVT vector
#define IDT_255_ADDR 1020 //start address of last IVT vector
#define IDT_VECTOR_SZ 4 //size of each IVT Vector (in bytes)
#define BP __asm{ int 0x3 } //break point
void main()
{
WORD csAddr; //Code segment of given interrupt
WORD ipAddr; //Starting IP for given interrupt
short address; //address in memory (0-1020)
WORD vector; //IVT entry ID (i.e., 0..255)
char dummy; //strictly to help pause program execution
vector = 0x0;
printf("\n---Dumping IVT from bottom up---\n");
printf("Vector\tAddress\t\n");
for
(
address=IDT_001_ADDR;
address<=IDT_255_ADDR;
address=address+IDT_VECTOR_SZ,vector++
)
{
printf("%03d\t%08p\t",vector,address);
//IVT starts at bottom of memory, so CS is alway 0x0
__asm__
(
".intel_syntax;"
"PUSH ES;"
"MOV AX, 0;"
"MOV ES,AX;"
"MOV BX,address;"
"MOV AX,ES:[BX];"
"MOV ipAddr,AX;"
"INC BX;"
"INC BX;"
"MOV AX,ES:[BX];"
"MOV csAddr,AX;"
"POP ES;"
);
printf("[CS:IP]=[%04X,%04X]\n",csAddr,ipAddr);
}
printf("press [ENTER] key to continue:");
scanf("%c",&dummy);
printf("\n---Overwrite IVT from top down---\n");
/*
Program will die somwhere around 0x4*
Note: can get same results via DOS debug.exe -e command
*/
for
(
address=IDT_255_ADDR;
address>=IDT_001_ADDR;
address=address-IDT_VECTOR_SZ,vector--
)
{
printf("Nulling %03d\t%08p\n",vector,address);
__asm__
(
".intel_syntax;"
"PUSH ES;"
"MOV AX,0;"
"MOV ES,AX;"
"MOV BX,address;"
"MOV ES:[BX],AX;"
"INC BX;"
"INC BX;"
"MOV ES:[BX],AX;"
"POP ES;"
);
}
return;
}/*end main()------------------------------------------------------------*/
Any help would be greatly appreciated. Once again my apologies if it is something obvious.
Actually you can pass C arguments to inline asm. But You have to define it after the asm code part.
In Your case something like this could work (You should add -masm=intel to the gcc's command line):
asm(
".intel_syntax noprefix;\n\t"
...
"MOV BX,%[address];\n\t"
...
".intel_syntax prefix;\n\t"
:: [address] "m" address, ...
: "AX", "BX", /* all changed registers to inform compiler to save them if needed */
);
See examples in a similar question.

Segmentation Fault: 11 when running C program

To try to display graphics using C, I am trying to take advantage of C's "inline assembly" feature. I get no errors during compilation, but when I try to run the program, I get this error:
Segmentation Fault: 11
Here is my code:
int main(){
asm("movb 0xc,%ah");
asm("movb $1,%al");
asm("movw $5,%cx");
asm("movw $5,%dx");
asm("int $0xc");
return 0;
}
Constructive criticism appreciated, insults not.
Thanks!
First, it looks like you're trying to use BIOS interrupts to do the graphics, but the graphics interrupt is int 10h (0x10), not 0xc, so you want to call int $0x10.
Second, you can't call most BIOS interrupts from within 32-bit or 64-bit Linux or Windows programs, so make sure you're compiling this for DOS. Otherwise, calling the invoke interrupt opcode on a BIOS interrupt will crash your program. And if you run a newer version of Windows, you'll probably still have to run your compiled program inside of an emulator like DOSBox for it to work properly.
Finally, GCC inline assembly has a certain format to it:
__asm__ __volatile__ (
assembler template
: output operands /* optional */
: input operands /* optional */
: list of clobbered registers /* optional */
);
So for example:
int main()
{
/* Set video mode: */
__asm__ __volatile__ (
"movb $0x0, %%ah \n\
movb $0x13, %%al \n\
int $0x10"
:
:
:"ax"
);
/* Draw pixel of color 1 at 5,5: */
__asm__ __volatile__ (
"movb $0xC,%%ah \n\
movb $1, %%al \n\
movw $5, %%cx \n\
movw $5, %%dx \n\
int $0x10"
:
:
:"ax","cx","dx"
);
/* Reset video mode: */
__asm__ __volatile__ (
"movb $0x0, %%ah \n\
movb $0x03, %%al \n\
int $0x10"
:
:
:"ax"
);
return 0;
}
But the optional fields are only really useful if you're writing functions in assembly language and want to pass in arguments from your C code.
Also, I don't have DJGPP and a DOS installation handy, so I can't test any of this code to make sure it works with the 32-bit protected mode binaries it generates, but hopefully I've hit the nail close enough on the head that you can handle the rest yourself. Good luck!

Resources