1.关于系统调用sys_write
Linux的系统调用通过int 80h实现,用系统调用号来区分入口函数,它的作用类似与dos的中断。
mov edx, len ; 参数三:字符串长度
mov ecx, msg ; 参数二:要显示的字符串
mov ebx, 1 ; 参数一:文件描述符(stdout)
mov eax, 4 ; 系统调用号(sys_write)
int 0x80 ; 调用内核功能
2.C与汇编混合编程
2.1 64位机器上目标文件不兼容问题: “could not read symbols"
如果我们按照书上的命令:
nasm -f -o foo.o foo.asmgcc -c o bar.o bar.c
ld -s -o foobar foo.o bar.o
假如你是在64b的机器上,就会收到出错信息:
“could not read symbols"
这是因为,你的foo.o &&bar.o 分别是32b的目标文件和64位的目标文件,所以没法使用链接器进行链接。
解决方法:统一使用32b的elf文件,命令如下
gcc -m32 -c -o bar.o bar.c
ld -m elf_i386 -s -o foobar foo.o bar.o
2.2参数传递问题
如果一个汇编中定义的函数想要被外部程序引用,需要用关键字导出——global; 如果汇编中用到其他文件定义的函数,需要对函数进行声明,导入——extern;参数入栈顺序——后面的参数先入栈3.ELF文件格式解析
3.1.为什么需要了解ELF文件格式
因为linux可执行内核是采用ELF文件格式的,将ELF格式的内核加载到内存之后,如何将控制权转移到内核——我们如何知道程序开始执行的起始地点相对ELF头的位置?加载内核到内存之后,程序应该如何执行?程序执行的时候使用的都是虚拟地址——在ELF文件格式中提供的都是虚拟地址。那么如何将程序加载到对应的虚拟地址?ELF文件格式中存储了很多冗余信息,程序也包含很多个不同的段,那么如何将这些段分别加载到不同的位置?program header一共有多少个,其中分别在文件中的偏移、长度和加载到虚拟地址的位置信息?
等等这些信息都需要我们了解ELF文件的格式。
3.2ELF文件格式概览
它的常用参数意义如下:
-u:使用大写字母显示内容;
-a:autoskip自动跳过空数据;
-g num:groupby分组大小 1表示1字节
-c cols:每行显示的列数
-l num:一共显示多少单元
-s +/-num:seek,起始单元多远的地方开始显示
2)elf文件格式与后续的相关部分
想要了解elf文件的具体信息,可以参考这里:elf文件格式完全解析
与后续内容相关的信息如下:
A、在ELF文件头中,包含程序的入口的虚拟地址;
B、每个段在ELF文件中的位置和大小信息,被加载到虚拟内存的位置和大小信息
4.调用原理
首先,我们知道,汇编调用C语言函数实际上是通过call指令来实现的。而call的对象是符号表中的一个符号,实际上,这个符号对应的是一个虚拟地址,也就是说符号表中的符号,是一个虚拟地址。那么call与jmp有什么区别呢
对于jmp的区别就是:一个是段内调用,一个是段间调用
对于call则有很大的不同,因为call的调用会对栈产生影响:
(1)call的近调用不会改变使用的栈,但是栈的内容发生了变化:下一条指令被压入栈;如果有参数,参数被压入栈
(2)call的远调用会改变使用的栈,由于使用的栈发生变化,因此对于参数有一个拷贝的过程。
保存当前的ss和esp到被调用过程的栈中
拷贝参数
保存当前的cs和eip到被调用过程的栈中
总结:call与jmp的主要区别在于对待返回地址的不同;call远和近调用区别在于对于堆栈ss和sp的信息保存。