分类:
2012-03-27 17:05:54
原文地址:GCC内嵌汇编语言& ADS/GCC汇编语法区别 作者:zsfly
AT&T 格式 | Intel 格式 |
pushl %eax | push eax |
AT&T 格式 | Intel 格式 |
pushl $1 | push 1 |
AT&T 格式 | Intel 格式 |
addl $1, %eax | add eax, 1 |
AT&T 格式 | Intel 格式 |
movb val, %al | mov al, byte ptr val |
AT&T 格式 | Intel 格式 |
ljump $section, $offset | jmp far section:offset |
lcall $section, $offset | call far section:offset |
AT&T 格式 | Intel 格式 |
lret $stack_adjust | ret far stack_adjust |
AT&T 格式 | Intel 格式 |
section:disp(base, index, scale) | section:[base + index*scale + disp] |
AT&T 格式 | Intel 格式 |
movl -4(%ebp), %eax | mov eax, [ebp - 4] |
movl array(, %eax, 4), %eax | mov eax, [eax*4 + array] |
movw array(%ebx, %eax, 4), %cx | mov cx, [ebx + 4*eax + array] |
movb $4, %fs:(%eax) | mov fs:eax, 4 |
__asm__(汇编语句模板: 输出部分: 输入部分: 破坏描述部分) |
__asm__ __volatile__("cli": : :"memory") |
__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x) ) |
__asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt)); |
Static __inline__ void __set_bit(int nr, volatile void * addr) { __asm__( "btsl %1,%0" :"=m" (ADDR) :"Ir" (nr)); } |
分类 | 限定符 | 描述 |
通用寄存器 | a | 将输入变量放入eax这里有一个问题:假设eax已经被使用,那怎么办?其实很简单:因为GCC 知道eax 已经被使用,它在这段汇编代码的起始处插入一条语句pushl %eax,将eax 内容保存到堆栈,然后在这段代码结束处再增加一条语句popl %eax,恢复eax的内容 |
b | 将输入变量放入ebx | |
c | 将输入变量放入ecx | |
d | 将输入变量放入edx | |
s | 将输入变量放入esi | |
d | 将输入变量放入edi | |
q | 将输入变量放入eax,ebx,ecx,edx中的一个 | |
r | 将输入变量放入通用寄存器,也就是eax,ebx,ecx,edx,esi,edi中的一个 | |
A | 把eax和edx合成一个64 位的寄存器(use long longs) | |
内存 | m | 内存变量 |
o | 操作数为内存变量,但是其寻址方式是偏移量类型,也即是基址寻址,或者是基址加变址寻址 | |
V | 操作数为内存变量,但寻址方式不是偏移量类型 | |
“” | 操作数为内存变量,但寻址方式为自动增量 | |
p | 操作数是一个合法的内存地址(指针) | |
寄存器或内存 | g | 将输入变量放入eax,ebx,ecx,edx中的一个或者作为内存变量 |
X | 操作数可以是任何类型 | |
立即数 | I | 0-31之间的立即数(用于32位移位指令) |
J | 0-63之间的立即数(用于64位移位指令) | |
N | 0-255之间的立即数(用于out指令) | |
i | 立即数 | |
n | 立即数,有些系统不支持除字以外的立即数,这些系统应该使用“n”而不是“i” | |
匹配 | 0 | 表示用它限制的操作数与某个指定的操作数匹配, |
1 | 也即该操作数就是指定的那个操作数,例如“0” | |
9 | 去描述“%1”操作数,那么“%1”引用的其实就是“%0”操作数,注意作为限定符字母的0-9 与指令中的“%0”-“%9”的区别,前者描述操作数,后者代表操作数。 | |
& | 该输出操作数不能使用过和输入操作数相同的寄存器 | |
操作数类型 | = | 操作数在指令中是只写的(输出操作数) |
+ | 操作数在指令中是读写类型的(输入输出操作数) | |
浮点数 | f | 浮点寄存器 |
t | 第一个浮点寄存器 | |
u | 第二个浮点寄存器 | |
G | 标准的80387浮点常数 | |
% | 该操作数可以和下一个操作数交换位置 例如addl的两个操作数可以交换顺序(当然两个操作数都不能是立即数) | |
# | 部分注释,从该字符到其后的逗号之间所有字母被忽略 | |
* | 表示如果选用寄存器,则其后的字母被忽略 |
sdt/ads 和 gcc支持的at&t格式汇编 是有语法上的不同的。
gcc的汇编语法,makefile,linker script file等可以参考uboot的项目
将ARM SDT下的汇编代码移植到GCC for ARM编译器时,经常要做如下修改:
1、[注释]
sdt/ads => gcc
; => /* */ 或者 //
2、[伪操作符替换]
sdt/ads => gcc
JUMPADDR => JUMPADDR: -- 符号定义加:号
INCLUDE => .INCLUDE
EQU => .equ
TCLK2 EQU PB25 => .equ TCLK2, PB25
TCLK2 EQU PB25 => .equ TCLK2, PB25
DCD => .long
IF :DEF: => #if defined(MACRO_SAMPLE)
ELSE => #else
ENDIF => #endif
:OR: => |
:SHL: => <<
Entry => Entry:
END => .end
AREA Word, CODE, READONLY => .text
AREA Block, DATA, READWRITE => .data
CODE32 => .arm
CODE16 => .thumb
LTORG => .ltorg
% => .fill
MACRO => .macro
MEND => .endm
EXPORT => .global
IMPORT => .extern
GBLL GBLA => .global
SETL SETA => #define 或者.equ
EQU => #define
GET option.a => #include "option.a"
?? => .align
3、[操作数及运算符号替换]
ldr pc, [pc, #&18] 替换成 ldr pc, [pc, #+0x18]
“&” => “+0x”
ldr pc, [pc, #-&20] 替换成 ldr pc, [pc, #-0x20]
“-&” => “-0x”