中国DOS联盟论坛

China DOS Union

-- Unite DOS · Advance DOS · Grow DOS --
Union site: www.cn-dos.net Forum site: www.cn-dos.net/forum
Guest | Log in | Register | Members | Search | China DOS Union
中国DOS联盟论坛
The time now is 2026-08-01 21:06
48,037 topics / 350,122 posts / today 2 new / 48,249 members
DOS开发编程 & 发展交流 (开发室) » Tried TC2, it seems that inline assembly is not supported?
Printable Version  1,502 / 5
Floor1 GOTOmsdos Posted 2006-06-24 03:46
铂金会员 Posts 1,827 Credits 5,154
Tried TC2, it seems that inline assembly is not supported? Is that the case?
Floor2 070 Posted 2006-06-24 21:05
高级用户 Posts 217 Credits 659 From 福建
Google search, keyword: TC inline assembly

According to the help system of TC2.0, it is said that in TC2.0, assembly language can be used. The method is to use the asm keyword: its format is asm opcode <operands> <;newline>, just like other comments, the content between <> is optional; for example:

main()
{
char *c="hello,world" $;
asm mov ah,9;asm mov dx,c;asm int 33;
printf("You sucessed! ");

}
Or:

main()
{
char *c="hello,world" $;
asm mov ah,9
asm mov dx,c
asm int 33
printf("You sucessed!");
}
The two formats are actually the same. If you use the first style, remember:
Each assembly statement must start with asm. If there are multiple sentences in one line, then never forget the semicolon (;) between the two sentences. But the semicolon after the last assembly statement (if there are no other statements after it) can be optional. For example, the semicolon after asm int 33; in the first example can be omitted because there are no other statements after it. But if it is like this:
asm mov ah,9; asm mov dx,c;asm int 33; printf("You sucessed!");
Then the semicolon after asm int 33; is still better to leave to avoid compilation errors! This is quite similar to the C language in this regard.

There is also a format asm{ assembly language statement}, this format should be generally welcomed.
Their examples are as follows (the statement arrangement format is the same as the above two):
asm{
mov ax,var1
add ax,var2
......
}
But note that this format is not supported by TC2.0!
Only later TC++3.0 and later IDEs support it!

Tool usage:
Once your C source file includes these good things, you must compile with the COMMAND-LINE of TCC.EXE. The specific command parameters are already provided by TCC.EXE, and I won't elaborate here. The simplest is: TCC C source file name (using this method, TCC will automatically call TASM.EXE and TLINK.EXE, and can make TLINK.EXE correctly find the required .obj and .lib files. If you compile step by step, you may encounter many problems. The main thing is that TLINK.EXE itself will not look for .obj and .lib files. You can build a .bat file by yourself. If you want to specify the directory of .lib files, you can use the /L parameter. There is an example later in the article). But everyone should pay attention, check whether there is a TASM.EXE file in your TC directory, and set some parameters in the TURBOC.CFG (this file includes the runtime parameters of TCC.EXE, all parameters in it will be automatically used by TCC.EXE during runtime, such as: -IH:TCINCLUDE -LH:TCLIB) file, and confirm that the version number of TASM.EXE is above 2.0, and whether it is downward compatible. But in most cases, there is no TASM.EXE in the TC directory, or the version is abnormal.
If you have the TASM.EXE file and the TURBOC.CFG file is also written, but you also need to pay attention to one problem: run TCC.EXE under an independent DOS SHELL (don't be afraid, this is not a new thing, I mean, don't run under the DOS SHELL in TC, for example. I once lost here. When I found it, I just wanted to beat the computer. Fortunately, I didn't, otherwise there would be no this article.)
There is also an important sentence: TC2.0 supports most 8086 instructions (of course, there are some conventions in usage, but I don't plan to explain them in detail now, because it is a very cumbersome thing. Maybe I will write it later - if you need it).
If the conventions I mentioned above are very cumbersome, then the following method is so simple!
Let's use the built-in variables of Borland for TC2.0 to perform pseudo-assembly.
Maybe you don't know that there are some built-in pseudo-registers in TC2.0 (can be regarded as register-type variables, but they are much more useful than register-type variables)
_AX, _AH, _AL,
_BX, _BH, _BL,
_CX, _CH, _CL,
_DX, _DH, _DL,
_DI, _SI, _SP,
_CS, _DS, _ES, _SS
Note the size of these registers. _AX, _BX, _CX, _DX, _CS, _DS, _ES, _SS, _SI, _DI, _SP, etc. are all 16-bit registers equivalent to the unsigned int type in C language. The rest are all 8-bit registers (equivalent to unsigned char) (How can TC support 32-bit registers, so EAX, etc. cannot be used. FS, GS and IP registers are all invalid). Also, when passing parameters, don't forget to use cast.
The interrupt call instruction is: __int__(interrupt_#) (note that both the prefix and suffix of int are two underscores)
For example:
#include<dos.h>
unsigned int _stklen=0x200;
unsigned int _heaplen=0;

main()
{
_DX=(unsigned int)"Hello,world. " $;
_AX=0x900;
__int__(0x21);

}
dos.h is the header file that contains the __int__() built-in interrupt call statement, so it is indispensable. _stklen and _heaplen are two internal reference variables (this is a term I thought of, meaning that if these two variables are explicitly declared in the source file, the compiler will refer to them to construct the information during compilation to generate the target file the user wants. If they are not explicitly declared, the compiler will automatically determine). There are also some conventions for these two variables. If _stklen is not explicitly declared and _heaplen is assigned zero, it means that the stack and heap are default.
Finally, there is an undocumented flag register flags in TC2.0, which is also a built-in pseudo-register: _FLAGS, which is a 16-bit register. These built-in registers can all be operated, but pay attention to the types they represent (perform type conversion when necessary);
Does this seem like a good way? (And using this method, as long as you use the dos.h header file, you don't need to compile with TCC, you can directly compile under the IDE of TC20).
TC2.0 also provides some simple and easy-to-use functions to implement calls to DOS functions such as: int86(...), int86x(...) (but these methods actually still call functions, so it is not as good as using pseudo-registers. Also, because it involves the memory allocation of the union REGS structure, the system overhead is increased, and using pseudo-registers is the most concise). Port communication functions such as: inportb(...), inport(...), outportb(...), outport(...), pointer conversion functions: FP_OFF, FP_SEG, MK_FP. These functions are all in the help system. You can refer to them when useful.


Example of tlinkbat.bat:
rem The lib environment variable is the directory of the .obj and .lib file
set lib=h: clib
rem The following sentence's c0s (C zero S) is an .OBJ file, which is a STARTUP file of a C program
tlink %lib%c0s %1,%1,%1,/L%lib%emu.lib %lib%maths.lib %lib%cs.lib
set lib=
(You can delete the sentences starting with rem when using)

___________________________________________________
Some conventions:
Let's first talk about the compilation principle of the compiler when writing assembly language (inline assembly - my own name, you can call it whatever you want) under TC20:
1. All assembly language statements outside the main() function are treated as data declaration statements, that is, they will be placed in the data segment during compiler compilation. For example:
asm string1 db "Hello,,,world!",0ah,0xd,$
main()
{
asm mov dx,offset string1
asm mov ah,9
asm int 33
asm mov dx,offset string2
asm int 33
}
asm string2 db "the string can be declared after the main() function!$"
Like this, the assembly language data definition statements outside main() (in fact, no matter what assembly statements, as long as they are outside main(), including this sentence: asm mov ax,0x4c00), are placed in the data segment after compilation, and the C language data declaration statements are still in accordance with C rules!
2. All assembly language statements inside the main() function are placed in the code segment after compilation, including this sentence:
asm string2 db "the string can be declared after the main() function!$"
3. Do not use C language keywords in assembly statements starting with asm, which will cause errors in the compilation stage

Then, what conclusion will you get according to these three items? (Close your eyes and think for a while, you may become very appreciative of yourself, yes, you should believe yourself is right!)
Let's take a look at this conclusion together:
1. According to compilation principle 1, it is concluded that: you cannot write assembly command statements outside main() (don't laugh, it is the same as C language, which is worth noting!), do not perform any segment definitions and macro definitions anywhere (this is because the compiled form determines it, that is, in TC20, all assembly format statements can only be direct data definitions and statement instructions)!
2 According to compilation principle 2, it is concluded that: you cannot use assembly statements to perform data definition inside main() (also don't laugh, most people will have such errors when writing assembly for the first time under TC20)
3. Things like class cast are not allowed in assembly statements starting with asm
Okay, the sky is bright and the air is clear! With this said, a general framework comes out! As long as you follow this principle, many inexplicable errors can be avoided!
In plain language:
The data definition of assembly statements is placed outside main(), and the instructions are placed inside main().
If you don't have better documentation, then remember my words!

Some details:
Escape characters of C are not supported in inline assembly statements starting with asm. But when a character array declared in C language (containing escape characters) is used, and the int 33 ah=9 function is used to output this string, the escape characters are valid (this is mainly because the internal representation forms are different after compilation, you can think about it yourself to get the answer).
Inline assembly supports some C-like things such as numerical representation, string declaration format, etc.
For example: a hexadecimal data can be represented in two ways: 0xa and 0ah, and the string can be like this: "Hello,world!$" (like C) or "Hello,world!$" (in the assembly's own way?.
Like C, you also need to pay attention to the type of assignment, and it is stricter than C (assembly never does things like type conversion by itself)
So everything is completely up to you to do well! And you don't try to do this in the form of C. For example, the format asm mov dx,(unsigned)a (a is such a thing, char a="hello,world!";), and this sentence will also cause an error: asm mov dx,word ptr a (logical error), but this is not a compilation error, but a runtime error (think about the specific reason yourself, like the operation effect and consequences of word label, etc.). You can use a sentence as an intermediary, such as int i=(unsigned)a; asm mov dx,i (also never use asm mov dx,(unsigned)a such a sentence. But, tell everyone a good news, you can use a pointer to point to a string, and then you will be surprised that you can do this: char *p="hello,world"; asm mov dx,p, and then use the int 33 ah=9 function to output this string without errors (this also shows the characteristics of the pointer, it is a two-byte (under TC20) variable, which contains an address, which has nothing to do with the type of the variable it points to).
Inline assembly statements do not support the -> operator. There is also the problem of labels. You will see some special features in the final example!


The above are just some small and minor things (also very common), and there are still many details to say, but due to my limited time, I can't list them one by one. For example, the application of C structures in inline assembly, you can think about the usage according to its operation mechanism; in addition, since this is just a learning matter, it is still better for everyone to learn by themselves (find some relevant documents, of course, there are not many complete ones now), the situation will be much better. I have learned a lot in the process of learning inline assembly, such as knowledge in compilation principles, and methods of how to make the code more efficient and occupy the least space, etc. Finally, I recommend a method to everyone. Using the -S switch of TCC can generate the assembly code of the C source file (maybe many people have used it) which is a very good learning material! I wish everyone success in learning!

Cstarter
02-11-17

/* Due to personal time and ability limitations, there are inevitable errors and details. Please forgive me!
My Email:wxe85@sina.com Cstarter1985@hotmail.com QQ:170594633 */
Some examples:
The following example is a rewrite of the program in Chapter 11 of "IBM-PC Assembly Language Programming" by Shen Meiming and Wen Dongchan, Tsinghua Edition. You can directly type tcc filename on the command line, of course, you need to have TASM.EXE
/*
asm mus_frep dw 330,294,262,294,3 dup(330)
asm dw 3 dup(294),330,392,392
asm dw 330,294,262,294,4 dup(330)
asm dw 294,294,330,294,262,-1
asm mus_time dw 6 dup(25),50
asm dw 2 dup (25,25,50)
asm dw 12 dup(25),100
*/
asm mus_frep dw 330,392,330,294,330,392,330,294,330
asm dw 330,392,330,294,262,294,330,392,294
asm dw 262,262,220,196,196,220,262,294,330,262
asm dw -1
asm mus_time dw 3 dup (50),25,25,50,25,25,100
asm dw 2 dup (50,50,25,25),100
asm dw 3 dup (50,25,25),100

main()
{
asm jmp start
/*Setting the frequency of sound generation, this section is detailed in Chapter 11 of "IBM-PC Assembly Language Programming" by Shen Meiming and Wen Dongchan, Tsinghua Edition */

sound:
asm mov al,0b6h
asm out 43h,al
asm mov dx,12h
asm mov ax,533h*896
asm div di
asm out 42h, al
asm mov al,ah
/* This delay is to prevent errors in the last operation of two IO operations, because the CPU is faster than the bus, so you need to delay and wait for the first operation to complete before performing the second operation */

asm mov cx,1000
delay:
asm loop delay

asm out 42h,al
asm in al,61h
asm mov ah,al
asm or al,3
asm out 61h,al

/* Using interrupt 15H function 86H to delay CX:DX=microseconds */
asm mov ax,2710h
asm mul bx
asm mov cx,dx
asm mov dx,ax
asm mov ah,86h
asm int 15h /* Can be replaced by __int__(0x15); */

asm mov al,ah
asm out 61h,al
asm jmp add_count
/*------------------*/
start:
asm mov si,offset mus_frep
asm lea bp,mus_time
frep:
asm mov di,
asm cmp di,-1
asm je end_mus
asm mov bx,
asm jmp sound
add_count: /* Labels cannot be written in assembly language */
asm add si,2
asm add bp,2
asm jmp frep
end_mus:;

}

For the above program, you can write one using the pseudo-register method, which is much easier!

/*A sound generation program! (quoted from "Inside PC Technology" Power Edition - this edition is not as good as Tsinghua Edition)*/
#includedos.h
main()
{
static union REGS ourregs;
outportb(0x43,0xb6);
outportb(0x42,0xee);
outportb(0x42,0);
outportb(0x61,(inportb(0x61)|0x03));
ourregs.h.ah=0x86;
ourregs.x.cx=0x001e;
ourregs.x.dx=0x8480;
int86(0x15,&ourregs,&ourregs);
outportb(0x61,(inportb(0x61)&0xfc));
}
Floor3 GOTOmsdos Posted 2006-06-25 02:13
铂金会员 Posts 1,827 Credits 5,154
main()
{
asm mov dx,offset string1
asm mov ah,9
asm int 33
asm mov dx,offset string2
asm int 33
}

TC2, he said: "in-line assembly not allowed in function main"
Floor4 Scott0902 Posted 2006-06-26 23:44
中级用户 Posts 237 Credits 466
TC2 is not supported, and BC must be supported
Floor5 zhgwbzhd Posted 2006-06-27 08:14
高级用户 Posts 187 Credits 506
Supported, I've used it to do things. I often use tc2 and bc2
Floor6 cnch Posted 2006-06-30 12:07
中级用户 Posts 70 Credits 326
TC2 supports inline assembly, but you need to add parameters when compiling
[ Contact the Union admin team - 中国DOS联盟 - Standard version ]
Sponsored by ifanr Inc | © 2001–2023