AT&T汇编语言及其寻址方式

汇编语言论风格来分主要是两类,一类是Intel汇编,一类是AT&T汇编,分别被Windows和Linux作为主流风格。因为我博客以推荐Linux系统为主,所以以后多以Linux汇编为主要描述语言。 

AT&T汇编的特点:

  ".s"为汇编语言的后缀名,

  "#"井号开头的是注释行,

  "."点开始的指令一般都是伪指令,

  "$"美元符号修饰立即数,

  "%"修饰寄存器。例如:

AT&T汇编寄存器,寄存器前需要加上%修饰:

  8位:al,ah

  16位:ax

 

  32位:eax

 

  64位:rax

AT&T操作符修饰:

  8位:b

  16位:w

  32位:l

  64位:q

操作格式:操作符[操作修饰符]   操作对象[源]   操作对象[目标]

 

寻址方式(Addrsing mode),就是指数据的组织方式,固定格式为:地址或偏移 (%基址或偏移量寄存器, %索引寄存器, 比例因子)

则 最终地址 = 地址或偏移 + %基址或偏移量寄存器 + %索引寄存器  * 比例因子

这一串东西基本上都是可选的,没写的项基本上算以0代替,不同的组合就成了不同的寻址方式,如下:

1) 直接寻址

movl ADDRESS, %eax

ADDRESS其实就相当于"地址或偏移"里的地址,反正就是一个数字。

 

2)寄存器寻址

其实上面的例子也包括了寄存器寻址,顾名思义%eax就是寄存器寻址,代表对这个寄存器本身的写入或读出。

 

3)立即寻址

movl $2, %ebx

我一直觉得立即寻址算不算寻址,反正它的意思就是把2这个数字写入%eax寄存器,$2就是立即寻址,其实就是立即数。

 

4)间接寻址

movl (%eax), %ebx

(%eax)就是间接寻址了,意思就是访问eax寄存器里的数值所代表的地址。相当于通用公式里的%基址或偏移量寄存器。

 

5)索引寻址(变址寻址)

movl 0xFFFF0000(,%eax,4), %ebx

0xFFFF0000(,%eax,4)就是索引寻址,意思是从0xFFFF0000地址开始,加上%eax * 4作为索引的最终地址。请自行匹配上面的通用公式。

 

6)基址寻址

movl 4(%eax), %ebx

4(%eax)就是基址寻址,意思是以eax寄存器里的数值作为基址,加上4得到最终地址。也可以匹配到上面的通用公式,而且这个是很常用的寻址方式。

 

AT&T与Intel的寻址表示不同:

(Intel)sub eax, [ebx + ecx * 4h - 20h]          

(AT&T)subl    -0x20(%ebx, %ecx, 0x4), %eax

上面表示缩放因子以及偏移量的立即数前不需要加$符号。

总结:Intel的寻址方式若表示为[<base register> + <index register> * <scale> + <offset>],则AT&T表示为:<offset>(<base register>, <index register>, <scale>)

 

常见汇编指令:

-------------------------------------------------------------------------------------------------------------------------
LEA   reg16,mem16                 目标地址传送指令: 将一个近地址指针写入到指定的寄存器。
-------------------------------------------------------------------------------------------------------------------------
其中reg16必须是一个16位通用寄存器,mem16必须是一个存储器,执行这个指令后,就将mem16所指的16位偏移地址传送reg16中。

比如: LEA AX,BUF     就是将存储器中BUF所指的地址传送给AX.

区别MOV传送指令:     MOV传送的是地址所指的内容,而LEA只是地址。
--------------------------------------------------------------
ADDL                清空堆栈参数
--------------------------------------------------------------
addl source, destination
--------------------------------------------------------------
MOV    (X)l w b        传送数据
--------------------------------------------------------------
movx source, destination
--------------------------------------------------------------
CMOV    (X)l w b        条件传送数据
--------------------------------------------------------------
cmovx source, destination

EFLAGS位    名称            描述
CF        进位(Carry)标志        数学表达式产生进位或者错位
OF        溢出(Overflow)标志    整数值过大或者过小
PF        奇偶校验(Parity)标志    寄存器包含数学操作造成的错误数据
SF        符号(Sign)标志        指出结果为正还是负
ZF        零(Zero)标志        数学操作的结果为零


指令对                    描述            EFLAGS状态
CMOVA/CMOVNBE                大于/小于或者不等于    (CF或者ZF)=0
CMOVAE/CMOVNB                大于或者等于/不小于    CF = 0
CMOVNC                    无进位            CF = 0
CMOVB/CMOVNAE                小于/不大于        CF = 1
CMOVC                    进位            CF = 1
CMOVBE/CMOVNA                小于或者等于/不大于    (CF或ZF) = 1
CMOVE/CMOVZ                等于/零            ZF = 1
CMOVNE/CMOVNZ                不等于/不为零        ZF = 0
CMOVP/CMOVPE                奇偶校验        PF = 1
CMOVNP/CMOVPO                非奇偶校验/奇偶验    PF = 0


指令对                    描述            EFLAGS状态
CMOVGE/CMOVNL                大于或者等于/不小于    (SF异域OF) = 0
CMOVL/CMOVNGE                小于/不大于或者等于    (SF民域OF) = 1
CMOVLE/CMOVNG                小于或者等于/不小于    ((SF异域OF)或ZF) = 1
CMOVO                    溢出            OF = 1
CMOVNO                    末溢出            OF = 0
CMOVS                    带符号(负)        SF = 1
CMOVNS                    无符号(非负)        SF = 0
--------------------------------------------------------------
XCHG                在两个寄存器之间或者存在内存位置之间交换值
--------------------------------------------------------------
cmovx operand1, operand2
--------------------------------------------------------------
BSWP                反转一个32位寄存器中的字节序
--------------------------------------------------------------
常应用于大小端交换
0~7位和24~31位进行交换
8~15位和16~23位交换
bswap %ebx
--------------------------------------------------------------
XADD                交换两个值并把总和存储在目标操作数中
--------------------------------------------------------------
xadd source, destination
--------------------------------------------------------------
CMPXCHG                把一个值和一个外部值进行比较,并且交换它和另一个值
--------------------------------------------------------------
cmpxchg source, destination
--------------------------------------------------------------
CMPXCHG8G            比较两个64位值并且交换它们
--------------------------------------------------------------
cmpxchg8b destination
--------------------------------------------------------------
PUSH (X) l w b            把新的数据项目存到堆栈
--------------------------------------------------------------
pushx source
--------------------------------------------------------------
POP (X) l w b            从堆栈中取回数据
--------------------------------------------------------------
popx destination

指令对                    描述
PUSHA/POPA                压入或者弹出所有16位通用寄存器
PUSHAD/POPAD                压入或者弹出所有32位通用寄存器
PUSHF/POPF                压入或者弹出EFLAGS寄存器的底16位
PUSHFD/POPFD
--------------------------------------------------------------
JMP                 跳转
--------------------------------------------------------------
jmp location
--------------------------------------------------------------
CALL                调用函数                
--------------------------------------------------------------
call address
--------------------------------------------------------------
RET                调用返回指令                
--------------------------------------------------------------

--------------------------------------------------------------
指令            描述                EFLAGS
--------------------------------------------------------------
JA            如果大于(above),刚转跳        CF = 0 与 ZF = 0
JAE            如果大于(above)或等于,则转跳    CF = 0
JB            如果小于(below),则转跳        CF = 1
JBE            如果小于(below)或等于,则转跑    CF = 1 或 ZF = 1
JC            如果进位,则转跳        CF = 1
JCXZ            如果CX寄存器为0,则跳转        
JECXZ            如果ECX寄存器为0,则跳转
JE            如果相等,则跳转            ZF = 1
JG            如果大于(greater),则跳转    ZF = 0 与 SF = OF
JGE            如果大于(greater)或等于,则跳转    SF = OF
JL            如果小于(less),则转跳        SF<>OF
JLE            如果小于(less)或者小于,则跳转    ZF = 1 或 SF <> OF
JNA            如果不大于(above),则跳转    CF = 1 或 ZF = 1
JNAE            如果不大于(above)或等于,则跳转    CF = 1
JNB            如果不小于(below),则转跳        CF = 0
JNBE            如果不小于(below)或等于,则跳转    CF = 0 与 ZF = 0
JNC            如果无进位,则转跳        CF = 0
JNE            如果不等于,则转跳        ZF = 0
JNG            如果不大于(greater),则跳转    ZF = 1 或 SF<>OF
JNGE            如果不大于(greater)或等于,则跳转 SF<>OF
JNL            如果不小于(less),则跳转        SF = OF
JNLE            如果不小于(less)或者小于,则跳转    ZF = 0 与 SF = OF
JNO            如果不溢出,则转跳        OF = 0
JNP            如果不奇偶校验,则转跳        PF = 0
JNS            如果无符号,则跳转        SF = 0
JNZ            如果非零,则跳转            ZF = 0
JO            如果溢出,则跳转            OF = 1
JP            如果奇偶校验,则转跳        PF = 1
JPE            如果偶校验,则跳出        PF = 1
JPO            如果奇偶校验,则跳转        PF = 0
JS            如果带符号,则跳转        SF = 1
JZ            如果为零,则跳转        ZF = 1
--------------------------------------------------------------
jxx address
--------------------------------------------------------------
CMP                比较指令                
--------------------------------------------------------------
cmp operand1, operand2

cmp %eax, %ebx
jeg greater

--------------------------------------------------------------
指令                描述                
--------------------------------------------------------------
CLC                清空进位标志(设置它为零)
CMC                对进位标志求反(把它改变为相反的值)
STC                设置进位标志(设置它为1)
--------------------------------------------------------------

--------------------------------------------------------------
INC                递增                
--------------------------------------------------------------

--------------------------------------------------------------
DEC                递减                            
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述                
--------------------------------------------------------------
LOOP                循环直到ECX寄存器为零
LOOPE/LOOPZ            循环直到ECX寄存器为零,或者没有设置ZF标志
LOOPNE/LOOPNZ            循环直到ECX寄存器为零,或者设置了ZF标志
--------------------------------------------------------------
loop address
--------------------------------------------------------------
MOVZX                用把零值加载到EBX中 (无符号)                            
--------------------------------------------------------------
EBX:ECX
movzx source, destination
--------------------------------------------------------------
MOVSX                用把零值加载到EBX中 (带符号)                            
--------------------------------------------------------------
EBX:ECX
movsx source, destination
--------------------------------------------------------------
MOVQ                把数据传送到MMX寄存器中                            
--------------------------------------------------------------
movq source, destination
--------------------------------------------------------------
MOVDQA/MOVDQU                用于把128位数据传送到MMX寄存器中,或者是MMX寄存器传送数据                            
--------------------------------------------------------------
movdqa source, destination

--------------------------------------------------------------
FLD                用于把浮点传送入和公传送出FPU寄传器                            
--------------------------------------------------------------
fld source
--------------------------------------------------------------
FBLD                集把80位打包BCD值加载到FPU寄存器中以及从FPU寄存获取这些值
FBSTP                同上                            
--------------------------------------------------------------
fbld source
--------------------------------------------------------------
FST                用于获取FPU寄存器堆栈中顶部位置,并且把这个值放到内存位置中
FSTS                同上,单精
FSTL                同上,双精    
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
FLD1                把+1.0压入FPU堆栈中
FLDL2T                把10的对数(底数2)压入FPU堆栈中
FLDL2E                把e的对数(底数2)压入FPU堆栈中
FLDPI                把PI值压入FPU堆栈中
FLDLG2                把2的对数(底数10)压入FPU堆栈中
FLDLN2                把2的对数(底数e)压入FPU堆栈中
FLDZ                把+0.0压入FPU堆栈中
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
MOVAPS                把4个对位的打包单精度值传送到XMM寄存器或者内存
MOVUPS                把4个不对准的打包单精度值传到XMM寄传器或者内存
MOVSS                把1个单精度值传送到内存或者寄存器的低双字节
MOVLPS                把2个单精度值传送到内存或者寄存器的低四字节
MOVHPS                把2个单精度值传送到内存或者寄存器的高四字节
MOVLHPS                把2个单精度从低四字传到高四字
MOVHLPS                把2个单精度值从高四字传送到低四字
MOVSHDUP (SSE3)            从内存或者XMM寄存器传送128位值,复制2个和第4个32位数据元素
MOVSLDUP (SSE3)            从内存或者XMM寄存器传送128位值,复制第1个和第3个32位数据元素
MOVDDUP     (SSE3)            从内存或者XMM寄存器传送64位双精度浮点值,把它复制到128位XMM寄存器中
--------------------------------------------------------------

--------------------------------------------------------------
指令                转换
CVTDQ2PD            打包双字整数到打包双精度FP(XMM)
CVTDQ2PS            打包双字整数到打包单精度FP(XMM)
CVTPD2DQ            打包双精度FP到打包双字整数(XMM)
CVTPD2PI            打包双精度FP到打包双字整数(XMM)
CVTPD2PS            打包双精度FP到打包单精度FP(XMM)
CVTPI2PD            打包双字整数到打包双精度FP(XMM)
CVTPI2PS            打包双字整数到打包单精度FP(XMM)
CVTPS2DQ            打包单精度FP到打包双字速度(XMM)
CVTPS2PD            打包单精度FP到打包双精度FP(XMM)
CVTPS2PI            打包双精度FP到打包双字整数(XMM)
CVTTPD2PI            打包双精度FP到打包双字整数(XMM,截断)
CVTTPD2DQ            打包双精度FP到打包双字整数(XMM,截断)
CVTTPS2DQ            打包单精度FP到打包双字整数(XMM,截断)
CVTTPS2PI            打包单精度FP到打包双字整数(XMM,截断)
--------------------------------------------------------------

--------------------------------------------------------------
ADD    (x)            用于把两个整数相加
--------------------------------------------------------------
add source, destination
-------------------------------------------------------------
ADC    (x)            带符号或者无符号整数,
                可以把值分割为多个双字数据元素并且对每个元素执行加法操作
-------------------------------------------------------------
adc source, destination
--------------------------------------------------------------
SUB    (x)            减法的基本形式
SBB    (X)            带借位减法指令
--------------------------------------------------------------
sub source, destination
--------------------------------------------------------------
MUL    (x)            无符号乘法
IMUL    (x)            带符号乘法
--------------------------------------------------------------
mul source
imul multiplier, source, destination
--------------------------------------------------------------
DIV    (x)            无符号除法
IDIV    (x)            带符号除法
--------------------------------------------------------------
div divisor
idiv divisor
--------------------------------------------------------------
SAL                向左算述移位
SHL                向左逻辑移位
SAR                移位除法 (符号操作GOOD)
SHR                移位除法 (小心位清0和正负数)
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
ROL                向左循环移位
ROR                向右循环位移
RCL                向左循环移位,并且包含进位标志
RCR                向右循环移位,并且包含进拉标志
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
AAA                调整加法操作的结果
AAS                调整减法操作的结果
AAM                调整乘法作的结果
AAD                准备除法操作的被除数
--------------------------------------------------------------

--------------------------------------------------------------
AND                位与
NOT                位非
OR                位或
XOR                异域
TEST                检查EFLAGS寄存器,

在8位、16位、32位值之间执行接位逻辑AND操作

并且相应地设置符号、零和奇偶校验标志,而且不修改目标值                
--------------------------------------------------------------
AND、OR、XOR指令格式
and source, destination
--------------------------------------------------------------
FSTSW                把状态寄存器读取到一个双字内存位置或者AX寄存器中
FSTCW                控制寄存器的设置加载到双字内存位置中查看设置内容
FLDCW                把双字内存值加载到控制寄存器中
FILDS                把一个双字整数值加载到FPU寄存器堆栈中
FISTS                获得寄存器堆栈顶部的值
FIST                助记符指定了S字符
FLDS/FLDL            加载内存中的单精度/双精度值
FST/FSTP            用于把ST0寄存器数据传送到另一个FPU寄存器或者数据从FPU寄存器传送到内存位置
FXCH                交换ST0寄存器和另一个FPU寄存器的值
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
FADD/FADDS            浮点加法/32位
FDIV                浮点除法
FDIVR                反向浮点除法
FMUL                浮点乘法
FSUB                浮点减法
FSUBR                反向浮点减法
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
F2XMI                计算2的乘方(次数为ST0中的值)减1
FABS                计算ST0中的值的绝对值
FCHS                改变ST0中的值的符号
FCOS                计算ST0中的值的余弦
FPATAN                计算ST0中的值的部分反正切
FPREM                计算ST0中的值除以ST1中的值部分余数
FPREM1                计算ST0中的值除以ST1中的值的IEEE部分余数
FPTAN                计算ST0中的值部分正切
FRNDINT                把ST0中的值舍入到最近的整数
FSCALE                把计算ST0乘以2的ST1次乘方
FSIN                计算ST0中的值的正弦
FSINCOS                计算ST0中的值的正弦和余弦
FSQRT                计算ST0中的值的平方根
FYL2X/FYL2X1            计算ST1*log ST0(以2为基数)
FYL2XPI                计算ST1*log(ST0+1)(以2为基数)
FSAVE                把所有FPU寄存器复制到一个108字节的内存位置
                ,然后初始化FPU状态
FRSTOR                恢复FPU时,所有FPU寄存器(包括数据寄存器)都被复为执行FSAVE指令时的状态
--------------------------------------------------------------

--------------------------------------------------------------
指令                描述
FNCLEX                清空浮点异常标志
FNSAVE                把FPU状态保存到内存中
FNSTCW                保存FPU控制寄存器
FNSTENV                把FPU操作环境保存到内存中
FSTSW                把FPU状态寄存器保存或者保存在AX寄存器中
SAHF                把AH寄存器的第0,2,4,6和7位分别传送到进位、奇偶校验、对准、零和符号标志,
                不影响EFLAGS寄存器中的其它位
FLDENV                把内存块的值加载回FPU环境中
--------------------------------------------------------------

--------------------------------------------------------------
MOVSB                传送单一字节
MOVSW                传送一个字(2字节)
MOVSL                传送一个双字(4字节)
--------------------------------------------------------------

--------------------------------------------------------------
STD                用于设置DF标志
CLD                将DF标志清零
--------------------------------------------------------------

--------------------------------------------------------------
REPE                等于时重复
REPNE                不等于时重复
REPNZ                不为零时重复
REPZ                为零时重复
--------------------------------------------------------------

--------------------------------------------------------------
LODSB                把一个字节加载到AL寄存器中
LODSW                把一个字(2字节)加载到AX寄存器中
LODSL                把一个双字(4字节)加载到EAX寄存器中
--------------------------------------------------------------

--------------------------------------------------------------
STOSB                存储AL寄存器中一个字节数据
STOSW                在座AX寄存器中一个字(2字节)的数据
STOSL                在座EAX寄存器中一个双字(4个字节)的数据
--------------------------------------------------------------

1..align abs-expr1, abs-expr2, abs-expr3

.align是存储对齐汇编命令,用于在当前子区中把位置计数器值设置(增加)到下一个指定存储边界处。第1个绝对值表达式abs-expr1(Absolute Expression)指定要求的边界对齐值。对于使用a.out格式目标文件的80x86系统,该表达式值是位置计数器值增加后其二进制值最右面0值位的个数,即是2的幂值。例如,".align 3"表示把位置计数器值增加到8的倍数上。如果位置计数器值本身就是8的倍数,那么就无需改变。但是对于使用ELF格式的80x86系统,该表达式值直接就是要求对齐的字节数。例如".align 8"就是把位置计数器值增加到8的倍数上。

第2个表达式给出用于对齐而填充的字节值。该表达式与其前面的逗号可以省略。若省略,则填充字节值是0。第3个可选表达式abs-expr3用于指示对齐操作允许填充跳过的最大字节数。如果对齐操作要求跳过的字节数大于这个最大值,那么该对齐操作就被取消。若想省略第2个参数,可以在第1和第3个参数之间使用两个逗号。

2..ascii "string"...

从位置计数器所指当前位置为字符串分配空间并存储字符串,可使用逗号分开写出多个字符串。例如,".ascii "Hello world!", "My assembler""。该汇编命令会让as把这些字符串汇编在连续的地址位置处,每个字符串后面不会自动添加0(NULL)字节。

3..asciz "string"...

该汇编命令与".ascii"类似,但是每个字符串后面会自动添加NULL字符。

4..byte expressions

该汇编命令定义0个或多个用逗号分开的字节值。每个表达式的值是1字节。

5..comm symbol, length

在bss区中声明一个命名的公共区域。在ld链接过程中,某个目标文件中的一个公共符号会与其他目标文件中同名的公共符号合并。如果ld没有找到一个符号的定义,而只是一个或多个公共符号,那么ld就会分配指定长度length字节的未初始化内存。length必须是一个绝对值表达式,如果ld找到多个长度不同但同名的公共符号,ld就会分配长度最大的空间。

6..data subsection

该汇编命令通知as把随后的语句汇编到编号为subsection的data子区中。如果省略编号,则默认使用编号0。编号必须是绝对值表达式。

7..desc symbol, abs-expr

用绝对表达式的值设置符号symbol的描述符字段n_desc的16位值。仅用于a.out格式的目标文件。参见有关include/a.out.h文件的说明。

8..fill repeat, size, value

该汇编命令会产生数个(repeat个)大小为size字节的重复拷贝。大小值size可以为0或某个值,但是若size大于8,则限定为8。每个重复字节内容取自一个8字节数。高4字节为0,低4字节是数值value。这3个参数值都是绝对值,size和value是可选的。如果第2个逗号和value省略,value默认为0值;如果后两个参数都省略,则size默认为1。

9..global symbol (或者.globl symbol)

该汇编命令会使得链接器ld能看见符号symbol。如果在我们的目标文件中定义了符号symbol,那么它的值将能被链接过程中的其他目标文件使用。若目标文件中没有定义该符号,那么它的属性将从链接过程中其他目标文件的同名符号中获得。这是通过设置符号symbol类型字段中的外部位N_EXT来做到的。参见include/a.out.h文件中的说明。

10..int expressions

该汇编命令在某个区中设置0个或多个整数值(80386系统为4B,同.long)。每个用逗号分开的表达式的值就是运行时刻的值,如".int 1234, 567, 0x89AB"。

11..lcomm symbol, length

为符号symbol指定的局部公共区域保留长度为length字节的空间。所在的区和符号symbol的值是新的局部公共块的值。分配的地址在bss区中,因此在运行时刻这些字节值被清零。由于符号symbol没有被声明为全局的,因此链接器ld看不见。

.comm  global_buffer 1111  /* 定义一块全局可见的、size为1111字节的内存 */
.lcomm  local_buffer  2222  /* 定义一块仅局部可见的、size为2222字节的内存 */

12..long expressions

含义与.int相同。

13..octa bignums

这个汇编命令指定0个或多个用逗号分开的16B大数(.byte, .word, .long, .quad, .octa 分别对应1、2、4、8和16字节数)。

14.org new_lc, fill

这个汇编命令会把当前区的位置计数器设置为值new_lc。new_lc是一个绝对值(表达式),或者是具有相同区作为子区的表达式,即不能使用.org跨越各区。如果new_lc的区不对,那么.org就不会起作用。请注意,位置计数器是基于区的,即以每个区作为计数起点。

当位置计数器值增长时,所跳跃过的字节将被填入值fill。该值必须是绝对值。如果省略了逗号和fill,则fill默认为0值。

15..quad bignums

这个汇编命令指定0个或多个用逗号分开的8B大数bignum。如果大数放不进8B中,则取低8B。

16..short expressions (同.word expressions)

这个汇编命令指定某个区中0个或多个用逗号分开的2字节数。对于每个表达式,在运行时刻都会产生一个16位的值。

17..space size, fill

该汇编命令产生size个字节,每个字节填值fill。这个参数为绝对值。如果省略了逗号和fill,那么fill的默认值就是0。

18..string "string"

定义一个或多个用逗号分开的字符串。在字符串中可以使用转义字符。每个字符串都自动附加一个NULL字符结尾。例如,".string "\n\nStarting", "other strings""。

19..text subsection

通知as把随后的语句汇编进编号为subsection的子区中。如果省略了编号subsection,则使用默认编号值0。

20..word expressions

对于32位机器,该汇编命令含义与.short相同。

 

 

https://www.cnblogs.com/orlion/p/5765339.html

http://blog.csdn.net/column/details/linuxcode.html

http://blog.csdn.net/jnu_simba/article/details/11747901

posted @ 2017-11-22 13:24  叕叒双又  阅读(3876)  评论(0编辑  收藏  举报