i386 asm 改写为 arm64 asm
前言: 最近刚读完 程序员的自我修养- 链接、装载与库一书。 最后一小节教我们怎样写一个最小的CRT 系统。书上基于的是i386 指令集来操作,所以内嵌汇编asm 的规则也是按照i386 指令集来的(至于什么精简指令集和复杂指令集,各种CPU架构之类的知识读者朋友自行Google,能力有限,不在这班门弄斧了)。由于本人从事 iOS 开发起家,所以一直用的 MACOS,也懒得切其他系统。这就导致两个系统支持的基本指令集不一致,这样编译成 xxx.a 自然会出错,不过个人比较执拗,不啃下这块骨头不舒服最终玩出了点门道(中间经历 无法言表)。 废话不多说,上主菜!
1、 i386 asm
//linux brk system call, brk 调整数据段内存地址,空出来的为堆内存分配空间
static int brk(void *end_data_segment)
{
int ret = 0;
// brk system call number: 45
// in /usr/include/asm-i386/unistd.h
// #define _NR_brk 45
asm("movl $45, %%eax \n\t"
"movl $1, %%ebx \n\t"
"int $0x80 \n\t"
"movl %%eax, %0 \n\t"
: "=r"(ret):"m"(end_data_segment));
return ret;
}
static int brk 是写在malloc.c 函数文件里面
命令行执行: clang -arch arm64 -c -fno-builtin -fno-stack-protector malloc.c 编译会报错
2. arm 64 //linux brk system call, brk 调整数据段内存地址,空出来的为堆内存分配空间
static int brk(void *end_data_segment)
{
long ret = 0;
// brk system call number: 45brk number: 69
// in /usr/include/asm-i386/unistd.h
// #define _NR_brk 45// brk number: 69
asm("mov x0, #69 \n\t"
"mov x1, #1 \n\t"
"svc #0 \n\t"
"mov %0, x0 \n\t"
: "=r"(ret):"m"(end_data_segment));
return ret;
}
修改点:
1. 寄存器修改: i386 上 %%eax, %%ebx 这些 对应到 arm64 64位上时 改写成 x0,x1(后面会放一个地址具体区别和对应都有)
2. src des 顺序修改 i386: instructions src des arm64 instructions des src 所以 "movl $45, %%eax, movl $1, %%ebx 修改为 mov x0, #45 , mov x1, #1
3. 系统调用问题: i386 int $0x80 改为 svc #0
4. $ 符号改为 # .
static int brk 是写在malloc.c 函数文件里面
5. 经过查证,发现brk 在i386下 系统调用号是45,但是在arm64下 找到的是sbrk(对brk封装),系统调用号为69
i386:
arm64:
修改之后 命令行: clang -arch arm64 -c -fno-builtin -fno-stack-protector malloc.c 编译就不会报错,下面的警告不是static int brk(void *end_data_segment) 内部的而是外部调用,正在修改中。
其他的asm 还在改造中!
linunx man 系统调用手册链接 这里面介绍比较全面,英文。耐心看完就最起码算能自己修改一些asm 汇编了。
brk number: 69