创建可被c、c++调用的汇编库

文章目录

  • 创建汇编方法
  • 编译c和汇编程序
  • 在c程序中使用汇编方法
  • 在c++中使用汇编
  • 创建静态库
  • 使用动态库
  • 调试汇编方法

创建汇编方法

  • 为了创建c语言可以使用的汇编方法,汇编方法必须遵循c语言的传值格式, 格式如下:
program stack
indirect addressing
Function paramter3 (16(%esp))
Function paramter2 (12(%esp))
Function paramter1 (8(%esp))
Return Address (4(%esp))
Old EBP Value ((%esp))
  • c语言中使用寄存器的功能
寄存器 状态
EAX 用来存储返回值,可以使用到程序返回前
EBX 被用来指向全局偏移表;值需要保留
ECX 可以使用
EDX 可以使用
EBP 值需要保留
ESP 值需要保留
EDI 值需要保留
ESI 值需要保留
ST(0) 用来存储浮点数返回值,可以使用到程序返回前
ST(1)-ST(7) 可以使用
  • 可以被c调用的汇编方法模板
.section .text
.type func, @function
func:
	pushl %ebp
	movl %esp, %ebp
	subl $12, %ebp
	pushl %edi
	pushl %esi
	pushl %ebx

	

	popl %ebx
	popl %esi
	popl %edi
	movl %ebp, %esp
	popl %ebp
	ret

编译c和汇编程序

  • 直接在gcc中包含汇编文件
    gcc -o mainprog mainprog.c asmfunc1.s
  • 使用汇编目标文件
    as -o asmfunc.o asmfunc.s
    gcc -o mainprog mainprog.c asmfunc.o
  • 示例
# asmfunc.s - An example of a simple assembly language function
.section .data
testdata:
	.ascii "This is a test message from the asm function\n"
datasize:
	.int 45
.section .text
.type asmfunc, @function
.globl asmfunc
asmfunc:
	pushl %ebp
	movl %esp, %ebp
	pushl %ebx
	
	movl $4, %eax
	movl $1, %ebx
	movl $testdata, %ecx
	movl datasize, %edx
	int $0x80

	popl %ebx
	movl %ebp, %esp
	popl %ebp
	ret

/* mainprog.c - An example of calling an assembly function */
#include 

int main()
{
	printf("This is a test. \n");
	asmfunc();
	printf("Now for the second time.\n");
	asmfunc();
	printf("This is complete the test.\n");
	return 0;
}

编译: gcc -o mainprog mainprog.c amsfunc.s
运行: ./mainprog
反汇编: objdump -D mainporg > dump

在c程序中使用汇编方法

  • 使用整数返回值
    c语言使用eax存放返回值,示例如下:
# sequare.s - An example of a function that returns an integer value
.type square, @function
.globl square
square:
	pushl %ebp
	movl %esp, %ebp
	movl 8(%ebp), %eax
	imull %eax, %eax
	movl %ebp, %esp
	popl %ebp
	ret

/* inttest.c - An example fo returning an integer value */
#include 

int main()
{
	int i = 2;
	int j  = square(i);
	printf("The square of %d is %d\n", i, j);

	j = square(10);
	printf("The square of 10 is %d\n", j);
	return 0;
}
  • 字符串返回值
    eax存放字符串的首地址
# cpuidfunc.s - An example of returning a string value
.section .bss
	.comm output, 13
.section .text
.type cpuidfunc, @function
.globl cpuidfunc
cpuidfunc:
	pushl %ebp
	movl %ebp, %esp
	pushl %ebx

	movl $0, %eax
	cpuid
	movl $output, %edi
	movl %ebx, (%edi)
	movl %edx, 4(%edi)
	movl %ecx, 8(%edi)
	movl $output, %eax
	popl %ebx
	movl %ebp, %esp
	popl %ebp
	ret

/* stringtest.c - An example of returning a string value */
#include 

char * cpuidfunc(void);

int main()
{
	char * spValue;
	spValue = cpuidfunc();
	printf("The CPUID is : %s \n", spValue);
	return 0;
}
  • 浮点数返回值
    浮点数使用ST(0)寄存器返回
# areafunc.s - An example of a floating point return value
.section .text
.type areafunc, @function
.globl areafunc
areafunc:
	pushl %ebp
	movl %ebp, %esp

	fldpi
	filds 8(%ebp),
	fmul %st(0), %st(0)
	fmul %st(1), %st(0)
	movl %ebp, %esp
	popl %ebp
	ret

/* floattest.c - An example of using floating point return values */
#include 

float areafunc(int);

int main()
{
	int radius = 10;
	float result;
	result = areafunc(radius);
	printf("The result is %f\n", result);

	result = areafunc(2);
	printf("The result is %f\n", result);
	return 0;
}
  • 使用多输入值
    函数传值从后向前,在栈中从高到低存储
# greater.s - An example of using multiple input values
.section .text
.type greater, @function
.globl greater
greater:
	pushl %ebp
	movl %esp, %ebp

	movl 8(%ebp), %eax
	movl 12(%ebp), %ecx
	cmpl %ecx, %eax
	jge end
	movl %ecx, %eax
end:
	movl %ebp, %esp
	popl %ebp
	ret

/* multest.c - An example of using multiple input values */
#include 

int main()
{
	int i = 10;
	int j = 20;
	int k = greater(i, j);
	printf("The larger value is %d\n", k);
	return 0;
}

在c++中使用汇编

由于c++中使用c++格式命名函数为了使用汇编必须使用c格式命名规则,所以在声明函数时需要以下格式生命:
extern “C”
{
int square(int);
}

创建静态库

  • ar 命令
选项 描述
d 从静态库中删除文件
m 移动静态库中的文件
p 将静态库中的指定文件打印到标准输出
q 快速添加一个文件到静态库
r 替换一个静态库中的文件
t 显示静态库中的文件列表
x 从静态库中提取文件
修饰符 描述
a 向一个存在文件的静态库中添加文件
b 向一个不存在文件的静态库中添加文件
c 创建一个新的静态库
f 截断静态库中的文件名
i 向一个不存在文件的静态库中添加文件
P 在静态库中使用全路径
s 为静态库创建索引
u 更新静态库中的文件
v 使用详细模式
  • 静态库的命名格式
    libx.a

  • 创建一个静态库
    ar r libchap.a square.o cpuidfunc.o areafunc.o greater.o fpmathfunc.o

  • 显示静态库中的文件
    ar tv libchap.a

  • 为静态库创建索引
    ranlib libchap.a

  • 显示静态库中的符号
    nm -s libchap.a | more

  • 使用静态库编译可执行文件
    gcc -o inttest inttest.c libchap.a

使用动态库

  • 命名格式
    libx.so

  • 生成动态库
    gcc -shared -o libchap.so square.o cpuidfunc.o areafunc.o greater.o fpmathfunc.o

  • 生成可执行文件
    gcc -o intest -L . -lchap inttest.c

  • 查看可执行文件中的动态库信息
    ldd inttest

  • 运行程序

    • 使用LD_LIBRARY_PATH环境变量指定动态库路径
      export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:."
      ldd inttest
      ./inttest

    • 使用/etc/ld.so.conf 指定动态库路径
      vim /etc/ld.so.conf
      ldconfig
      ldd inttest
      ./inttest

调试汇编方法

  • 给需要调试的汇编方法加上调试信息
		as -gstabs -o square.o square.s 
		gcc  -gstabs -o inttest inttest.c square.o
		gdb -q inttest

你可能感兴趣的:(汇编)