From: "Alexei A. Frounze" Newsgroups: comp.os.msdos.djgpp Subject: Re: 'retf' in inline? Date: Sun, 09 Apr 2000 11:21:22 +0400 Organization: MTU-Intel ISP Lines: 389 Message-ID: <38F02F72.A7C88440@mtu-net.ru> References: <38EFFFE0 DOT B217D192 AT home DOT com> NNTP-Posting-Host: ppp98-207.dialup.mtu-net.ru Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------321B74DB222A04F00D51A48A" X-Trace: gavrilo.mtu.ru 955269577 33394 212.188.98.207 (9 Apr 2000 08:39:37 GMT) X-Complaints-To: usenet-abuse AT mtu DOT ru NNTP-Posting-Date: 9 Apr 2000 08:39:37 GMT X-Mailer: Mozilla 4.61 [en] (Win95; I) X-Accept-Language: en,ru To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Reply-To: djgpp AT delorie DOT com This is a multi-part message in MIME format. --------------321B74DB222A04F00D51A48A Content-Type: text/plain; charset=koi8-r Content-Transfer-Encoding: 7bit Hi Mark! I think this will help you... Regards, Alexei A. Frounze ----------------------------------------- Homepage: http://alexfru.chat.ru Mirror: http://members.xoom.com/alexfru --------------321B74DB222A04F00D51A48A Content-Type: text/plain; charset=koi8-r; name="djasm.txt" Content-Transfer-Encoding: 8bit Content-Disposition: inline; filename="djasm.txt" DJGPP QuickAsm Programming Guide Okay, so this tutorial has long been overdue, I've been putting it off for a couple of months; but right now I'm in the mood to write it so here it is. This is just a short tutorial on doing assembly code using DJGPP. I am NOT teaching how to code x86 asm (get another tutorial or book); but I'll try to show how to do both inline and external asm in DJGPP. I assume you are already familiar with "standard" Intel asm, as used in TASM, MASM, etc. I highly suggest reading the FAQ lists first, faq102.zip and faq202b.zip, and the online docs, inside the txi*.zip package. There is also a newsgroup, comp.os.msdos.djgpp. The main site is located at DJGPP Homepage, where the most up-to-date information is available on DJGPP and where the mail archives are kept. I find many helpful articles in the mail archives. --------------------------------------------------------------------------- AT&T x86 Asm Syntax DJGPP uses AT&T asm syntax. This is a little bit different from the regular Intel format. The main differences are: * AT&T syntax uses the opposite order for source and destination operands, source followed by destination. * Register operands are preceded by the "%" character, including sections. * Immediate operands are preceded by the "$" character. * The size of memory operands are specified using the last character of the opcode. These are "b" (8-bit), "w" (16-bit), and "l" (32-bit). Here are some examples: (Intel equivalent in parentheses) movw %bx, %ax (mov ax, bx) xorl %eax, %eax (xor eax, eax) movw $1, %ax (mov ax,1) movb X, %ah (mov ah, byte ptr X) movw X, %ax (mov ax, word ptr X) movl X, %eax (mov eax, X) Most opcodes are identical between AT&T and Intel format, except for these: movsSD (movsx) movzSD (movzx) Where S and D are the source and destination operand size suffixes, respectively. For example, "movswl %ax, %ecx (movsx ecx, ax)". cbtw (cbw) cwtl (cwde) cwtd (cwd) cltd (cdq) lcall $S,$O (call far S:O) ljmp $S,$O (jump far S:O) lret $V (ret far V) [GOTCHA!] ] Opcode prefixes should NOT be written on the same line as the instruction they act upon. For example, "rep" and "stosd" should be two separate instructions, but the latter immediately following the former. Memory references are a little bit different too. The usual Intel memory reference of the form SECTION:[BASE + INDEX*SCALE + DISP] is written as SECTION:DISP(BASE, INDEX, SCALE). Here are some examples: (Intel equivalent in parentheses) movl 4(%ebp), %eax (mov eax, [ebp+4]) addl (%eax,%eax,4), %ecx (add ecx, [eax + eax*4]) movb $4, %fs:(%eax) (mov fs:eax, 4) movl _array(,%eax,4), %eax (mov eax, [4*eax + array]) movw _array(%ebx,%eax,4), %cx (mov cx, [ebx + 4*eax + array]) Jump instructions always use the smallest displacements. The following instructions always work in byte displacements only, however: "jcxz", "jecxz", "loop", "loopz", "loope", "loopnz" and "loopne". As suggested in the online docs, a "jcxz foo" could be expanded to work: jcxz cx_zero jmp cx_nonzero cx_zero: jmp foo cx_nonzero: [GOTCHA!] ] The online docs also caution on "mul" and "imul" instructions. The expanding multiply instructions are done using ONE operand. For example, "imul $ebx, $ebx" will NOT put the result in "edx:eax". Use the single operand form "imul %ebx" to get the expanded result. --------------------------------------------------------------------------- Inline Asm I'll start with inline asm first, because it seems to be the more frequently asked question. This is the basic syntax, as described in the online help: __asm__(asm statements : outputs : inputs : registers-modified); The four fields are: * asm statements - AT&T form, separated by newline * outputs - constraint followed by name in parentheses, separated by comma * inputs - constraint followed by name in parentheses, separated by comma * registers-modified - names separated by comma The simplest example: __asm__(" pushl %eax\n movl $1, %eax\n popl %eax" ); [GOTCHA!] ] You don't always have to use the other three fields, as long as you don't want to specify any input/output variables and you're NOT accidentally clobbering any registers. Let's spice it up with input variables. int i = 0; __asm__(" pushl %%eax\n movl %0, %%eax\n addl $1, %%eax\n movl %%eax, %0\n popl %%eax" : : "g" (i) ); /* i++; */ Don't panic yet! =) I'll try to explain first. Our input variable is "i" and we want to increment it by 1. We don't have any output variables, nor clobbered registers (we save "eax" ourselves). Therefore the second and last fields are empty. [GOTCHA!] ] Since the input field is specified, we need to leave a blank colon for the output field, but none for the last field, since it isn't used. Leave a newline or at least one space between two blank colons. Let's move on to the input field. Constraints are just instructions you give to the compiler to handle the variables they act upon. They are enclosed in double quotes. So what does the '"g"' mean? '"g"' lets the compiler decide where to load the value of "i" into, as long as the asm instructions accept it. In general, most of your input variables can be constrained as '"g"', letting the compiler decide how to load them (gcc might even optimize it!). Other commonly used constraints are "r" (load into any available register), "a" (ax/eax), "b" (bx/ebx), "c" (cx/ecx), "d" (dx/edx), "D" (di/edi), "S" (si/esi), etc. The one input we have will be referred to as "%0" inside the asm statements. If we have two inputs, they will be "%0" and "%1", in the order listed in the input fields (see next example). For N inputs and NO outputs, "%0" through "%N-1" will correspond to the inputs, in the order they are listed. [GOTCHA!] ] If ANY of the input, output, or registers-modified fields are used, register names inside the asm statements must be preceded with two percent ("%") characters, instead of one. Constrast this example with the first one, which didn't use any of the last three fields. Let's do two inputs and introduce "volatile": int i=0, j=1; __asm__ __volatile__(" pushl %%eax\n movl %0, %%eax\n addl %1, %%eax\n movl %%eax, %0\n popl %%eax" : : "g" (i), "g" (j) ); /* i = i + j; */ Okay, this time around we have two inputs. No problem, the only thing we have to remember is "%0" corresponds to the first input ("i" in this case), and "%1" to "j", which is listed after "i". [GOTCHA!] ] Oh yeah, what exactly is this "volatile" thing? It just prevents the compiler from modifying your asm statements (reordering, deleting, combining, etc.), and assemble them as they are (yes, gcc will optimize if it feels like it!). I suggest using "volatile" most of the time, and from here on we'll be using it. Let's do one which uses the output field this time. int i=0; __asm__ __volatile__(" pushl %%eax\n movl $1, %%eax\n movl %%eax, %0\n popl %%eax" : "=g" (i) ); /* i=1; */ This looks almost exactly like one of our previous input field examples; and it is really not very different. All output constraints are preceded by an equal ("=") character. They are also referred from "%0" to "%N-1" inside the asm statements, in the order they are listed in the output field. You might ask what happens if one uses both the input and output fields? Well, the next example will show you how to use them together. int i=0, j=1, k=0; __asm__ __volatile__(" pushl %%eax\n movl %1, %%eax\n addl %2, %%eax\n movl %%eax, %0\n popl %%eax" : "=g" (k) : "g" (i), "g" (j) ); /* k = i + j; */ Okay, the only unclear part is just the numbering of the variables inside the asm statements. I'll explain. [GOTCHA!] ] When using both input and output fields: [*** ] %0 ... %K are the outputs [*** ] %K+1 ... %N are the inputs In our example, "%0" refers to "k", "%1" to "i", and "%2" to "j". Simple, no? So far we haven't used the last field, registers-modified, at all. If we need to use any register inside our asm statements, we either have to "push" or "pop" them explicitly, or list them in this field and let gcc take care of that. Here's the previous example, without the explicit "eax" save and restore. int i=0, j=1, k=0; __asm__ __volatile__(" movl %1, %%eax\n addl %2, %%eax\n movl %%eax, %0" : "=g" (k) : "g" (i), "g" (j) : "ax", "memory" ); /* k = i + j; */ We tell gcc that we're using register "eax" in the registers-modified field and it will take care of saving or restoring, if necessary. A 16-bit register name covers 32-, 16- or 8-bit registers. [GOTCHA!] ] If we are also touching memory (writing to vars, etc.), it's recommended to specify '"memory"' in the registers-modified field. This means all our examples here should have had this specified (well, except the very first one), but I chose not to bring this up until now, just for simplicity. Local labels inside your inline asm should be terminated with either "b" or "f", for backward and forward references, respectively. For example, __asm__ __volatile__(" 0:\n ... jmp 0b\n ... jmp 1f\n ... 1:\n ... ); --------------------------------------------------------------------------- External Asm Blah... Okay fine. Here's a clue: Get some of your C/C++ files, and compile them as "gcc -S file.c" Then inspect file.S. The basic layout is: .file "myasm.S" .data somedata: .word 0 ... .text .globl __myasmfunc __myasmfunc: ... ret Macros, macros! There's an include file in which is convenient for writing external asm files. Just include it on top of your asm source and use the macros accordingly. For example, here's myasm.S: #include .file "myasm.S" .data .align 2 somedata: .word 0 ... .text .align 4 FUNC(__MyExternalAsmFunc) ENTER movl ARG1, %eax ... jmp mylabel ... mylabel: ... LEAVE That should be a good skeleton for your external asm code. --------------------------------------------------------------------------- Other Resources The best way to learn all these is to look at others' code. There's some inline asm code in the "sys/farptr.h" file. Also, if you run Linux, FreeBSD, etc., somewhere in the kernel source tree (i386/ or something), there are plenty of asm sources. Check the djgpp2/ dir at x2ftp.oulu.fi, for graphics/gaming libraries that have sources. If you have asm code that needs to be converted from Intel to AT&T syntax, or just want to stick with regular Intel syntax, you can: * Get NASM, a free assembler which takes Intel asm format and produces COFF binaries compatible with DJGPP * Get MASM and compile your sources to COFF format (object file format used by DJGPP) * Get ta2asv08.zip, a TASM to AT&T asm converter * Get o2cv10.arj to convert .OBJ/.LIB between TASM and DJGPP * Search the mail archives for a sed script that converts Intel to AT&T syntax --------------------------------------------------------------------------- 1/12/97 icbm AT IRC GREETS IdealNet & EFNET IRC #c and #gamecode Thanks to all people behind DJGPP! Mail me corrections/suggestions/complaints/crap at avly AT castle DOT net Copyright ¿ 1996 avly AT castle DOT net All Rights Reserved All trademarks mentioned are of their respective companies. Standard Disclaimer There are absolutely no guarantees, expressed or implied, on anything that you find in this document. I cannot be held responsible for anything that results from the use or misuse of this document. --------------321B74DB222A04F00D51A48A--