C Inline Asm Int 0x10 - c

I'm attempting to write a function that prints strings the screen in C. It's for a boot loader so there are no external libraries or anything linked in. Here's my function:
void printString(const char* pStr) {
while(*pStr) {
__asm__ __volatile__ (
"movb 0x0e, %%ah\n"
"movb %[c], %%al\n"
"int $0x10\n"
:
: [c] "r" (*pStr)
: "ax"
);
++pStr;
}
}
When I run this, I don't get any errors in my VM. It just sits there with the cursor in the upper left corner of the screen. Any thoughts? I can produce an objdump -d if anyone thinks it will be helpful.

Okay after some helpful comments, I may just go with full assembly. Something like
Print:
push %ax
movb $0x0E, %ah # Set interrupt code
movb $0x00, %bh # Set page #
.loop:
lodsb # Load next char
test %al, %al # Check for \0
je .done
int $0x10 # Call interrupt
jmp .loop
.done:
pop %ax
ret
That should be 16-bit real mode compatible and can be assembled with GAS, which, as I understand it, works better than GCC for compiling 16-bit programs.

I think you're missing the point. The problem isn't your assembly code; the problem is that "int 10" is a BIOS
If you've already booted to an OS (e.g. Windows or Linux), then your x86 CPU is running in "protected mode"; and you probably don't have access to int 10 from user space ... unless something like a Windows command prompt emulates it for you.
As far as Linux/assembly programming in general, I strongly recommend this (free, on-line, very good) book:
Programming from the Ground Up, Jonathan Bartlett
Thank you for clarifying that you're writing a "boot loader". Strong suggestion1: boot your custom code from a USB stick, or create a virtual DOS floppy to boot a DOS VM (either VMWare or VBox VMs, for example).
Here are some tutorials:
http://www.codeproject.com/Articles/36907/How-to-develop-your-own-Boot-Loader
https://cs.au.dk/~sortie/dopsys/osdev/
http://wiki.osdev.org/Rolling_Your_Own_Bootloader

Related

Stuck on porting OpenGL API loader implemented by 64-bit masm to that implemented by 32-bit

I am recently porting a OpenGL API loader implemented by 64-bit masm to that of 32-bit, part of 64-bit source codes are as follows:
.code
extrn __blue_glCore_glMultiDrawArraysIndirectBindlessCountNV: qword
glMultiDrawArraysIndirectBindlessCountNV proc
mov r11, __blue_glCore_glMultiDrawArraysIndirectBindlessCountNV
jmp r11
glMultiDrawArraysIndirectBindlessCountNV endp
extrn __blue_glCore_glCopyTexImage1D: qword
glCopyTexImage1D proc
mov r11, __blue_glCore_glCopyTexImage1D
jmp r11
glCopyTexImage1D endp
...
e.g. external symbol __blue_glCore_glMultiDrawArraysIndirectBindlessCountNV will be load when calling glMultiDrawArraysIndirectBindlessCountNV. My 32-bit modifications(change all qword to dword, all r11 to eax) are:
.model flat
.code
extrn __blue_glCore_glMultiDrawArraysIndirectBindlessCountNV: dword
glMultiDrawArraysIndirectBindlessCountNV proc
mov eax, __blue_glCore_glMultiDrawArraysIndirectBindlessCountNV
jmp eax
glMultiDrawArraysIndirectBindlessCountNV endp
extrn __blue_glCore_glCopyTexImage1D: dword
glCopyTexImage1D proc
mov eax, __blue_glCore_glCopyTexImage1D
jmp eax
glCopyTexImage1D endp
When other targets link this loader during compilation, the compiler(I used Visual Studio 2019) complains unresolved external symbol error. I actually know little about MASM, who can help me out?
Update1
I have created a mini demo in this repo to reproduce this problem, which can be built directly with Visual Studio and cmake. In particular, these lines puzzle me:
GLint major = 0, minor = 0;
//these two symbol are found
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
//this symbol is missed
glActiveTexture(0);
why only symbols of opengl1.0 and 1.1(opengl32.lib) loaded while others missed?
Update2
My Visual Studio linker complains:
Severity Code Description Project File Line Suppression State
Error LNK1120 1 unresolved externals test_bluegl E:\CPPCode\projects\bluegl\build\Debug\test_bluegl.exe 1
Error LNK2019 unresolved external symbol _glActiveTexture#4 referenced in function "private: virtual void __thiscall bluegl::BlueGLTest_GetVersion_Test::TestBody(void)" (?TestBody#BlueGLTest_GetVersion_Test#bluegl##EAEXXZ) test_bluegl E:\CPPCode\projects\bluegl\build\test_bluegl.obj 1
then I use dumpbin.exe to check generated symbol in bluegl.lib:
...
55DF0 _glActiveTexture#0
...
So I changed the corresponding proc to:
extrn __blue_glCore_glActiveTexture: dword
glActiveTexture proc param : dword
mov edx, __blue_glCore_glActiveTexture
jmp edx
glActiveTexture endp
Now the generated symbol was right and linking is OK, but new problems arose:
Visual Studio will report:
Severity Code Description Project File Line Suppression State
Error LNK2026 module unsafe for SAFESEH image. test_bluegl E:\CPPCode\projects\bluegl\build\bluegl.lib(BlueGLCoreWindowsImpl.obj) 1
Error LNK1281 Unable to generate SAFESEH image. test_bluegl E:\CPPCode\projects\bluegl\build\Debug\test_bluegl.exe 1
without setting /safeseh property for the masm source.
2 It's too heavy to append parameter list for each api, and I don't know why 64-bit masm not requiring parameter list.
Select a C implementation as workaround, but still interested in a masm32 implementation.

Get signatures of exported functions of a system DLL

How do you get the signature of an exported function of a DLL? I know this is possible since a program analysis tool such as IDA (and ollydbg) manages to get the following for GetVersionExA:
push offset VersionInformation ; lpVersionInformation
mov edi, offset dword_4D3B94
mov esi, offset aSS ; "%s - %s"
call GetVersionExA
Using a hex editor to search through PDBs, I could not find the string lpVersionInformation. So where and how can I extract the signature?

enable/disable cache on intel 64bit machine: CD bit always set?

I'm trying to disable all level of cache for my machine Intel(R) Xeon(R) CPU E5-1650 v2 # 3.50GHz in Xen. I wrote a tool to call the following assemble code to disable/enable the cache and show the CR0 register's value.
case XENMEM_disable_cache:
__asm__ __volatile__(
"pushq %%rax\n\t"
"movq %%cr0,%%rax\n\t"
"orq $0x40000000,%%rax\n\t"
"movq %%rax,%%cr0\n\t"
"movq %%cr0, %0\n\t"
"wbinvd\n\t"
"popq %%rax"
: "=r"(cr0)
:
:);
// gdprintk(XENLOG_WARNING, "gdprintk:XENMEM_disable_cache disable cache!
// TODO IMPLEMENT\n");
printk("<1>printk: disable cache! cr0=%#018lx\n", cr0);
rc = 0;
break;
case XENMEM_enable_cache:
__asm__ __volatile__(
"pushq %%rax\n\t"
"movq %%cr0,%%rax\n\t"
"andq $0xffffffffbfffffff,%%rax\n\t" /*~0x4000000*/
"movq %%rax,%%cr0\n\t"
"movq %%cr0, %0\n\t"
"popq %%rax"
: "=r"(cr0)
:
:);
printk("<1>printk: enable cache; cr0=%#018lx\n", cr0);
rc = 0;
break;
case XENMEM_show_cache:
__asm__ __volatile__(
"pushq %%rax\n\t"
"movq %%cr0, %%rax\n\t"
"movq %%rax, %0\n\t"
"popq %%rax"
: "=r"(cr0)
:
:);
// gdprintk(XENLOG_WARNING, "gdprintk:XENMEM_show_cache_status! CR0 value is
// %#018lx\n", cr0);
printk("<1>printk: XENMEM_show_cache_status! CR0 value is %#018lx\n", cr0);
return (long)cr0;
The code can compile and run. After I run the disable cache code, the system becomes extremely slow, which confirms the cache is disabled. In addition, the value of CR0 shows the CD bit is set when I run the disable cache code.
However, when I run the show cache code, the output shows the CD bit of CR0 is 0, no matter I disable/enable cache.
My question is:
Is the CD bit(30bit) of CR0 register always set 1 when cache is disabled?
If not, there must be something wrong with my code, could you please help me point out the error I made?
ANSWER:
The above code only set the CD bit of the CR0 register on the core where the code is running. We need to use the smp_call_function() to call the code on all cores!
My new question is:
If I disable cache and then enable cache using the above code, the CD bit of CR0 is cleared. However, the system's performance is still very very slow, just like when I disable the cache. So it seems to me that enabling the cache code does NOT work? However, since CD bit has been cleared, the enabling cache code should have worked! So the question is: How long should I wait after I enable cache so that I can have the same performance just like the performance before I disable cache?
BTW, when I run the enble cache code, the printk output shows that the CR0's CD bit is 0.
If you're on an SMP system, you should invoke the disable-cache code for every core with smp_call_function(), since it is theoretically possible that your show-cache code is running on a different processor. To use that function, #include <include/linux/smp.h>.
EDIT: smp_call_function() invokes the function pointer it is given only on other cores, not on the current one. Make sure to run the function on all cores by invoking the function yourself on the core that invokes smp_call_function().

How to write inline assembly in FreeDOS

I'm trying to write the following program to dump the interrupt vector table using FreeDOS in a virtual machine. I know that DEBUG will allow me to write an assembly program, but how do I create the following IVTDUMP.COM file, save it and run it?
Note: I'd like to try and do it all straight from FreeDOS if possible. I tried using the EDIT command but it errors out and I'm pretty sure I'm missing something.
for
(
address=IDT_255_ADDR;
address>=IDT_001_ADDR;
address=address-IDT_VECTOR_SZ,vector--
)
{
printf("%03d %08p ",vector,address);
__asm
{
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);
}
Things like for, address and printf are not part of assembly. You will have to rewrite that to actual assembly code or copy the macros and assembler you want to use to your freedos environment.
If you want to use debug as included in freedos you can use the a command to start writing assembly instructions, the n command to give a name and w to write the code to the file.
C:\debug
-a
06BC:0100 int 20
06BC:0102
-n ivtdump.com
-rcx 2
-w
Writing 0002 bytes.
-q
C:\
This sample program only exits the program through int 20. (The 2 after rcx indicates the length of the program to write to disk)

how to create .com files using masm 5.10?

.model tiny
.code
org 100h
host:
mov ah,9
mov dx,offset hi
int 21h
mov ax,4c00h
int 21h
hi db 'HELLO'
end host
c: masm hello.asm
output of this says operand expected on line 1. Please tell me how to generate com files using this version of masm...
I know this is raising a long dead thread but I thought I'd chime in here as I could not find the answer to this online very easily.
Cannot be done with 5.1, however you can use EXE2BIN (just search on google) to convert it to a com file.
You can also use 6.11 which can be found at http://www.phatcode.net/downloads.php?id=175.
Once you have that running, your hello world app would be:
.MODEL TINY
.DOSSEG ; Make sure you are using dos segment CODE, DATA + STACK
.DATA
MSG DB "Hello, World!", 0Dh, 0Ah, '$'
.CODE
.STARTUP ; Setup the starting address otherwise you'll see:
; LINK : warning L4055: start address not equal to 0x100 for /TINY
MOV AH, 09h
MOV DX, OFFSET MSG
INT 21h
MOV AH, 4Ch
INT 21h
END
To compile: ML /AT HELLO.ASM (the /AT enables .MODEL TINY)
It should compile without warnings or errors tested on MASM 6.11 under MS-DOS 6.22 in DOSBOX.
Hope this helps someone who had the same issue as I.
It can be done in MASM 5.1 (or older). From the MASM 5.0 docs, here is the basic shell with your test program.
TITLE COMFILE
_TEXT SEGMENT
ASSUME CS:_TEXT,DS:_TEXT,ES:_TEXT,SS:_TEXT
ORG 100H
START:
mov ah,9
mov dx,offset hi
int 21h
mov ax,4c00h
int 21h
hi db 'HELLO','$'
_TEXT ENDS
END START
With the above file named COMFILE.ASM, assemble and convert to .com using the following steps:
A>MASM COMFILE;
Microsoft (R) Macro Assembler Version 5.00
Copyright (C) Microsoft Corp 1981-1985, 1987. All rights reserved.
51668 + 464828 Bytes symbol space free
0 Warning Errors
0 Severe Errors
A>LINK COMFILE;
Microsoft (R) Overlay Linker Version 3.60
Copyright (C) Microsoft Corp 1983-1987. All rights reserved.
LINK : warning L4021: no stack segment
A>EXE2BIN COMFILE.EXE COMFILE.COM
Which should produce:
A>DIR COMFILE.COM
Volume in drive A has no label
Directory of A:\
COMFILE COM 18 01-01-80 12:00p
1 File(s) 30208 bytes free
A>COMFILE.COM
HELLO
A little thread necromancy here, yes. I also wasn't able to find a clear, working example of this elsewhere so hopefully this will help someone in the future.
MASM 6.0 was the first version of MASM capable of using the tiny memory model and therefore the first version of MASM capable of producing COM files. It's not terribly difficult to find copies of MASM 6.11 around the internet, and MASM 6.11 is still capable of being used under pure DOS if necessary.
Source: http://support.microsoft.com/kb/24954

Resources