DJGPP uses the assembly syntax of the AT&T format. It's a little different from the usual Intel format syntax. The main differences are as follows:
The at&t syntax reverses the position of the source and destination operands, and the purpose operand is after the source operand. The register operand must have a% prefix, and the immediate operand must have a prefix of $ sign. The size of the memory operand depends on the last character of the opcode. They are B (8-bit), W (16-bit), and L (32-bit).
Here are some examples. The left part is the Intel instruction format, and the right side is the at&t format.
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 of the instructions, at%t and Intel are similar, except for these:
movsSD // movsx
movzSD // movz
S and D resolution represent source and destination operand suffixes.
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
The prefix cannot be written on the same line as the instructions they are acting on. For example, rep and Stosd should be two separate instructions, and the memory situation is a little different. Usually the Intel format is as follows:
Section:[base + Index*scale + disp]
Be written as:
Section:disp (base, index, scale)
Here are some examples:
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])
The Jump instruction is usually a short jump. However, the following instructions are only allowed to jump within a byte range: Jcxz, Jecxz, Loop, Loopz, Loope, LOOPNZ, and Loopne. As the online documentation says, a JCXZ foo can be extended to the following jobs:
jcxz cx_zero
jmp cx_nonzero
cx_zero:
jmp foo
cx_nonzero:
The documentation also notes the MUL and Imul directives. The extended multiplication instruction uses only one operand, for example, Imul $EBX, $EBX will not put the result into edx:eax. Use the single operand in the Imul%EBX to obtain the extended results.
Inline ASM
I will start inline ASM first, because there seems to be a lot of doubt about it. This is the most basic syntax, as described in the online Help information:
__asm__ (ASM statements:outputs:inputs:registers-modified);
The meanings of these four fields are:
asm statements - AT&T 的结构, 每新行都是分开的。
outputs - 修饰符一定要用引号引起来, 用逗号分隔
inputs - 修饰符一定要用引号引起来, 用逗号分隔
registers-modified - 名字用逗号分隔
一个小小的例子:
__asm__("
pushl %eax\n
movl $1, %eax\n
popl %eax"
);
If you don't have to go to a particular input or output variable or modify the value of any register, you won't normally use the other three fields,
Let's analyze the 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)
); // increment i
Don't be bothered by the code above! I will try my best to explain it. We want the input variable i plus 1, we don't have any output variables, and we don't change the register value (we saved the EAX value). Therefore, the second and last fields are empty. Because the input field is specified, we still need to keep an empty output field, but there is no last field because it is not in use. Leave a new line or at least one space between the two empty colons.