gcc汇编
来源:互联网 发布:java 超时异常 编辑:程序博客网 时间:2024/06/11 03:48
转自http://blog.chinaunix.net/u1/48280/showart_1423294.html
1.gcc嵌入汇编
(1). 在gcc嵌入汇编中输入输出使用相同的寄存器?
- static void * __memcpy(void * to, const void * from, size_t n)
- {
- int d0,d1,d2;
- __asm__ __volatile__(
- "rep;movsl/n/t"
- "testb $2,%b4/n/t"
- "je 1f/n/t"
- "movsw/n"
- "1:/ttestb $1,%b4/n/t"
- "je 2f/n/t"
- "movsb/n"
- "2:"
- :"=&c" (d0), "=&D" (d1), "=&S" (d2)
- :"0" (n/4), "q" (n), "1" ((long) to), "2" ((long) from)
- :"memory");
- return (to);
- }
操作数0,1,2和3,5,6使用相同的寄存器的理解:
a. 3,5,6在输入过程中将值n/4,to和from的地址读入ecx,edi,esi寄存器中;
b. 0,1,2在输出过程中将ecx,edi,esi寄存器中的值存入d0,d1,d2内存变量中。
c. 注意在上面的语句中也有"&"限定符,但输入和输出仍使用相同的寄存器,如操作数0和3都使用寄存器ecx,这是因为"0"限定的结果,如果
把"0" (n/4)换成"c" (n/4),则因为"=&c"的限定而使得编译时报错。
(2). 关于gcc嵌入式汇编中"&"限定符的作用?
"&"限定符用于输出操作数,使其唯一的使用某寄存器
- int bar,foo;
- __asm__ __volatile__(
- "call func /n/t"
- "mov ebx,%1"
- :"=a" (foo)
- :"r" (bar));
在gcc编译时默认会让bar也使用eax寄存器,如果把"=a"改为"=&a",那么foo将唯一使用eax,而让bar使用其它的寄存器。
(3). _start和main的关系?
main是gcc看到的程序入口点,而ld和as所看到的程序入口点其实是_start。libc库中的_start会调用main函数。
a. 编译带_start的汇编程序时的步骤:as -o a.o a.s,ld -o a a.o; gcc -g -c a.s,ld -o a a.o。(使用gcc编译可以增加调试选项-g,这
时不能直接用gcc -o a a.s编译的原因是gcc会默认在程序中查找main函数,并且会将libc中的_start加入进来。如果直接用gcc -o a a.s编译
,则会报两个错误"重复的_start"和"没找到main")
b. 编译带main的汇编程序或C程序时的步骤:gcc -o a a.s;gcc -o a a.c。
(4).section和.previous
将这两个.section和.previous中间的代码汇编到各自定义的段中,然后跳回去,将这之后的的代码汇编到上一个section中(一般是.text段),
也就是自定义段之前的段。.section和.previous必须配套使用。
2. AT&T汇编
(1).data,.section等都是伪操作,不能直接翻译成机器码,只有相应的assembler才能识别
(2).section将程序分成几个片断,如.data,.text,.bss
(3).globl 函数名表示该函数被export,并可以被其它文件中的函数调用
(4).bss可以用来申请一块空间,但不需要对其进行初始化
(5)使用内核定义函数如open,read等可以通过int $80中断来完成
(6)MOVL $FOO,%EAX是把FOO在内存中的地址放到EAX中,而MOVL FOO,%EAX是把FOO这个变量的内容放入EAX
(7).include "文件名",将其它文件包含进来
(8)如何在汇编中表示结构?如c语言中的如下结构:
- struct para
- {
- char Firstname[40];
- char Lastname[40];
- char Address[240];
- long Age;
- }
- 在汇编中可以表示成:
- .section data
- record1:
- .ascii "Fredrick/0"
- .rept 31 #Padding to 40 bytes
- .byte 0
- .endr
- .ascii "Bartlett/0"
- .rept 31 #Padding to 40 bytes
- .byte 0
- .endr
- .ascii "4242 S Prairie/nTulsa, OK 55555/0"
- .rept 209 #Padding to 240 bytes
- .byte 0
- .endr
- .long 45
其中.rept n和.endr表示重复两者之间的序列n次,可用于填充数据
(9)当汇编程序由多个文件构成时,可以采用以下方式编译与连接:
as write-records.s -o write-records.o (gcc -g -c write-records.s)
as write-record.s -o write-record.o (gcc -g -c write-record.s)
ld write-record.o write-records.o -o write-records
(10)如何在汇编语言中使用动态库中的函数?
#helloworld-lib.s
.section .data
helloworld:
.ascii "hello world/n/0"
.section .text
.globl _start
_start:
pushl $helloworld
call printf
pushl $0
call exit
as helloworld-lib.s -o helloworld-lib.o
ld -dynamic-linker /lib/ld-linux.so.2 -o helloworld-lib helloworld-lib.o -lc
产生动态库:ld -shared write-record.o read-record.o -o librecord.so
(11)使用汇编文件生成动态库
as write-record.s -o write-record.o
as read-record.s -o read-record.o
ld -shared write-record.o read-record.o -o librecord.so
as write-records.s -o write-records.o
ld -L . -dynamic-linker /lib/ld-linux.so.2 -o write-records -lrecord write-records.o
记得运行write-records时还需要将动态库路径加到/etc/ld.so.conf中,并运行ldconfig
(12)编译汇编文件时如何产生调试符号
as --gstabs a.s -0 a.o 或者gcc -g -c a.s
附录:
(1)函数调用时栈的情况
#Parameter #N <--- N*4+4(%ebp)
#...
#Parameter 2 <--- 12(%ebp)
#Parameter 1 <--- 8(%ebp)
#Return Address <--- 4(%ebp)
#Old %ebp <--- (%ebp)
#Local Variable 1 <--- -4(%ebp)
#Local Variable 2 <--- -8(%ebp) and (%esp)
(2)例子
- .include "external_func.s"
- .section .data
- data_array: #定义long型数组
- .long 3,67,34,0
- data_strings: #定义字符串
- .ascii "Hello there/0"
- data_long: #定义long型变量
- .long 5
- .section .bss
- .lcomm my_buffer, 500 #申请一块500字节的内存
- .section .text
- .equ LINUX_SYSCALL, 0x80 #定义符号LINUX_SYSCALL的值为0x80
- .globl _start
- _start:
- pushl %edx
- movl data_long,%edx #将data_long变量的值放入edx寄存器
- movl $data_long,%edx #将data_long的地址放入edx寄存器
- popl %edx
- pushl $3 #push second argument
- pushl $2 #push first argument
- call power #call the function
- addl $8, %esp #move the stack pointer back
- pushl %eax #save the first answer before,calling the next function
- movl $1, %eax #exit (%ebx is returned)
- int $LINUX_SYSCALL
- .type power, @function #定义函数power
- power:
- pushl %ebp #save old base pointer
- movl %esp, %ebp #make stack pointer the base pointer
- subl $4, %esp #get room for our local storage
- movl 8(%ebp), %eax #put first argument in %eax
- movl 12(%ebp), %ebx #put second argument in %ebx
- imull %ebx,%eax
- movl %ebp, %esp #restore the stack pointer
- popl %ebp #restore the base pointer
- ret