gcc汇编

来源:互联网 发布:java 超时异常 编辑:程序博客网 时间:2024/06/11 03:48
转自http://blog.chinaunix.net/u1/48280/showart_1423294.html

1.gcc嵌入汇编
(1). 在gcc嵌入汇编中输入输出使用相同的寄存器?
  1. static void * __memcpy(void * to, const void * from, size_t n) 
  2. int d0,d1,d2; 
  3. __asm__ __volatile__( 
  4.    "rep;movsl/n/t" 
  5.    "testb $2,%b4/n/t" 
  6.    "je 1f/n/t" 
  7.    "movsw/n" 
  8.    "1:/ttestb $1,%b4/n/t" 
  9.    "je 2f/n/t" 
  10.    "movsb/n" 
  11.    "2:" 
  12.    :"=&c" (d0), "=&D" (d1), "=&S" (d2) 
  13.    :"0" (n/4), "q" (n), "1" ((long) to), "2" ((long) from) 
  14.    :"memory"); 
  15. 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嵌入式汇编中"&"限定符的作用?
"&"限定符用于输出操作数,使其唯一的使用某寄存器
  1. int bar,foo; 
  2. __asm__ __volatile__( 
  3. "call func /n/t" 
  4. "mov ebx,%1" 
  5. :"=a" (foo) 
  6. :"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语言中的如下结构:
  1. struct para 
  2. char Firstname[40]; 
  3. char Lastname[40]; 
  4. char Address[240]; 
  5. long Age;//4 bytes 
  6. 在汇编中可以表示成: 
  7. .section data 
  8. record1: 
  9. .ascii "Fredrick/0" 
  10. .rept 31 #Padding to 40 bytes 
  11. .byte 0 
  12. .endr 
  13. .ascii "Bartlett/0" 
  14. .rept 31 #Padding to 40 bytes 
  15. .byte 0 
  16. .endr 
  17. .ascii "4242 S Prairie/nTulsa, OK 55555/0" 
  18. .rept 209 #Padding to 240 bytes 
  19. .byte 0 
  20. .endr 
  21. .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)例子
  1. .include "external_func.s" 
  2. .section .data 
  3. data_array:      #定义long型数组 
  4. .long 3,67,34,0          
  5. data_strings:     #定义字符串 
  6. .ascii "Hello there/0" 
  7. data_long: #定义long型变量 
  8. .long 5 
  9. .section .bss 
  10. .lcomm my_buffer, 500    #申请一块500字节的内存 
  11. .section .text 
  12. .equ LINUX_SYSCALL, 0x80 #定义符号LINUX_SYSCALL的值为0x80 
  13. .globl _start 
  14. _start: 
  15. pushl %edx 
  16. movl data_long,%edx      #将data_long变量的值放入edx寄存器 
  17. movl $data_long,%edx     #将data_long的地址放入edx寄存器 
  18. popl %edx 
  19. pushl $3       #push second argument 
  20. pushl $2       #push first argument 
  21. call power     #call the function 
  22. addl $8, %esp #move the stack pointer back 
  23. pushl %eax     #save the first answer before,calling the next function 
  24. movl $1, %eax #exit (%ebx is returned) 
  25. int $LINUX_SYSCALL      
  26. .type power, @function #定义函数power 
  27. power: 
  28. pushl %ebp          #save old base pointer 
  29. movl %esp, %ebp     #make stack pointer the base pointer 
  30. subl $4, %esp       #get room for our local storage 
  31. movl 8(%ebp), %eax #put first argument in %eax 
  32. movl 12(%ebp), %ebx #put second argument in %ebx 
  33. imull %ebx,%eax 
  34. movl %ebp, %esp     #restore the stack pointer 
  35. popl %ebp           #restore the base pointer 
  36. ret 

原创粉丝点击