1.代码
foo.asm
;编译链接的方法
;(id的'-s'选项意为"strip all")
;
;$ nasm -f elf foo.asm -o foo.o
;$ gcc -c bar.c -o bar.o
;$ id -s hello.o bar.o foobar
;$ ./foobar
;the 2nd one
;$
extern choose ;int choose(int a,int b)
[section .data] ;数据在此
num1st dd 3
num2nd dd 4
[section .text] ;代码在此
global _start ;我们必须导出 _start 这个入口,以便让链接器识别
global myprint ;导出这个函数为了让bar.c使用
_start:
push dword [num2nd] ;'.
push dword [num1st] ;|
call choose ;|choose(num1st,num2nd);
add esp,8 ;/
mov ebx,0
mov eax,1 ;sys_exit
int 0x80 ;系统调用
;void myprint(char* msg,int len)
myprint:
mov edx,[esp + 8] ;len
mov ecx,[esp + 4] ;msg
mov ebx,1
mov eax,4 ;sys_write
int 0x80 ;系统调用
ret
bar.c
void myprint(char* msg,int len);
int choose(int a,int b)
{
if(a>=b) {
myprint("the 1st one\n",13);
}
else {
myprint("the 2nd one\n",13);
}
return 0;
}
2.编译连接+执行(32位)
> ls
bar.c foo.asm
> nasm -f elf32 -o foo.o foo.asm
> gcc -m32 -c -o bar.obar.c
> ld -m elf_i386 -s -o foobar foo.o bar.o
> ls
bar.c bar.o foo.asm foobar foo.o
> ./foobar
the 2nd one
3.代码解释
extern:EXTERN 伪操作告诉编译器当前的符号不是在本源文件中定义的,而是在其他源文件中定义的,在本源文件中可能引用该符号。如果本源文件没有实际引用该符号,该符号将不会被加入到本源文件的符号表中。
global:关键字,把符号导出到其他模块中。global是extern的对立面,如果一个模块声明一个extern的符号,然后引用它,为了防止链接错误,另外某一个模块必须确实定义了该符号,然后把它声明为global。
1.由于在bar.c中用到函数myprint(),所以要用关键字global将其导出
2.由于用到本文件外定义的函数choose(),所以要用关键字extern声明
3.myprint()和choose()遵循的都是C调用约定,后面的参数先入栈,并由调用者清理堆栈
dd:伪指令——定义双字。其后的每个操作数占用二个字(低字在前)。 DD还可以把其后的变量或标号的偏移地址和所在段首址存入存储器内指定 的双字单元(即DD前面的变量)中,第一个字中存放DD后的变量的偏移地址, 第二个字中存放该变量所在段的段首址。
push:入栈操作,遵守FILO原则(first in last out),而且必须是字操作。
dword:是双字,也就是32位,可以用来储存32位整数或者32位内存地址。[拓展:byte是字节,也就是8位,用来储存char或者char类型指针。word是字,也就是16位。用来储存16位整数或者16位地址]
add:操作数相加。ADD OPRD1,OPRD2。
1.OPRD1为任一通用寄存器或存储器操作数,可以是任意一个通用寄存器,而且还可以是任意一个存储器操作数。
2.OPRD2为立即数,也可以是任意一个通用寄存器操作数.立即数只能用于源操作数。
3.OPRD1和OPRD2均为寄存器是允许的,一个为寄存器而另一个为存储器也是允许的, 但不允许两个都是存储器操作数。
4.加法指令运算的结果对CF、SF、OF、PF、ZF、AF都会有影响.以上标志也称为结果标志.加法指令适用于无符号数或有符号数的加法运算。
--------------------------------------------------------//32bit或64bit版本
生成的.o文件必须都是32位或者都是64位:
-------------------------------------gcc 命令行参数:
-m32:生成32位代码
-m64:生成64位代码
-------------------------------------连接时版本注明:
-m elf_i386 :32位
-m elf_x86_64:
-m elf32_x86_64:
-------------------------------------编译时版本注明:
-f elf64:64位
-f elf32:32位
---------------------------------------------------------//命令行
-c:只编译并生成目标文件
./:表示当前目录的全路径,一般不在系统环境变量path中的可执行文件 ,运行的时候都要这样运行,当然写成绝对路径也行