欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

算法下午茶系列-重温汇编(6)[理解AT&T汇编的节]

程序员文章站 2022-03-02 17:21:10
...

首先,我们看一下AT&T汇编各段的意义

 

 

含义
.text 已编译程序的机器代码
.rodata 只读数据,如pintf和switch语句中的字符串和常量值
.data 已初始化的全局变量
.bss 未初始化的全局变量
.symtab 符号表,存放在程序中被定义和引用的函数和全局变量的信息
.rel.text 当链接器吧这个目标文件和其他文件结合时,.text节中的信息需修改
.rel.data 被模块定义和引用的任何全局变量的信息
.debug 一个调试符号表。
.line 原始C程序的行号和.text节中机器指令之间的映射
.strtab 一个字符串表,其内容包含.systab和.debug节中的符号表

 

上面列表也许比较抽象,我们从一个C程序生成的中间汇编代码分析:

#include <stdio.h>

void main(){

   char *x="xxxx";

   char y[]="yy";//y的16进制ASCII码是97,9797的十进制为31097

   printf("%s-----%s",x,y);

   exit(0);

}

   我们使用gcc -S testcr.c,查看编译生成的汇编代码(为便于理解,将生成的汇编代码进行了注释)

.file	"testcr.c"

	.section	.rodata

.LC0:

	.string	"xxxx"#使用char *分配

.LC1:

	.string	"%s-----%s"

	.text

.globl main

	.type	main, @function

main:

	pushl	%ebp

	movl	%esp, %ebp

	andl	$-16, %esp

	subl	$32, %esp#分配32字节栈空间,根据变量情况分配

	movl	$.LC0, 24(%esp)#x变量使用指针(4个字节大小),放入栈中,可以看到,变量分配靠近栈空间的尾部

	movw	$31097, 29(%esp)#字符'yy'移到main程序的栈中,直接将y变量的值放入栈中

	movb	$0, 31(%esp)#加上NULL标志,表示字符结束 

	movl	$.LC1, %eax

	leal	29(%esp), %edx

	movl	%edx, 8(%esp)

	movl	24(%esp), %edx

	movl	%edx, 4(%esp)

	movl	%eax, (%esp)

	call	printf

	movl	$0, (%esp)

	call	exit

	.size	main, .-main

	.ident	"GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"

	.section	.note.GNU-stack,"",@progbits

 

 

 

在MAIN函数中char *分配在只读数据段中,实际使用时,只在程序栈中分配一个指针的空间。char[] 在程序栈中分配空间,然后直接使用movl、movw之类的汇编直接把值放入栈中空间。那么在其它函数中声明的呢,可以从以下程序中看出,仍然如此。

 

#include <stdio.h>

void myprinf(){

   char *x="xxxx";

   char y[]="yy";//y的16进制ASCII码是97,9797的十进制为31097

   printf("%s-----%s",x,y);

}

void main(){

   int num=1;

   myprint();

   exit(0);

}

 

 

生成的中间汇编代码为:

.file	"testcr.c"

	.section	.rodata

.LC0:

	.string	"xxxx"

.LC1:

	.string	"%s-----%s"

	.text

.globl myprinf

	.type	myprinf, @function

myprinf:

	pushl	%ebp

	movl	%esp, %ebp

	subl	$40, %esp

	movl	$.LC0, -16(%ebp)

	movw	$31097, -11(%ebp)

	movb	$0, -9(%ebp)

	movl	$.LC1, %eax

	leal	-11(%ebp), %edx

	movl	%edx, 8(%esp)

	movl	-16(%ebp), %edx

	movl	%edx, 4(%esp)

	movl	%eax, (%esp)

	call	printf

	leave

	ret

	.size	myprinf, .-myprinf

.globl main

	.type	main, @function

main:

	pushl	%ebp

	movl	%esp, %ebp

	andl	$-16, %esp

	subl	$32, %esp

	movl	$1, 28(%esp)

	call	myprint

	movl	$0, (%esp)

	call	exit

	.size	main, .-main

	.ident	"GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"

	.section	.note.GNU-stack,"",@progbits

 

 

内存的常用分配方式有:

第一,静态分配,所有名字在编译时绑定某个存储位置。不能在运行时改变
第二,栈分配,活动时压入系统栈。
第三,堆分配,以任意次序分配