1.结构体ioctl_trans:

struct ioctl_trans {

unsigned long cmd;

ioctl_trans_handler_t handler;

struct ioctl_trans *next;

};

该结构体提供了一个粘合层,用户可以动态注册一个ioctl_trans以便其提供64位和32位的粘合:

extern int register_ioctl32_conversion(unsigned int cmd,

ioctl_trans_handler_t handler);

extern int unregister_ioctl32_conversion(unsigned int cmd);

整个系统的ioctl_trans连接成一个哈希表,放在ioctl32_hash_table变量中。每一个ioctl_trans的handler都是一个回调函数,在其中将64位的数据和32位的数据类型进行统一,统一成64位可以正确识别和处理的,以防在后续的64位代码中出错,比如一个32位的signed int为-1,需要将之转化成64个1而不是32个0加上32个1。

2.一套完整的系统调用:

如果不这样的话,32位程序的系统调用如何被路由到通过ioctl_trans们进行粘合的代码就成了问题,要知道x86-64已经不使用int 0x80作为触发系统调用的机制了,而使用syscall指令来触发。那么原来的32位程序都是用int 0x80来触发的,这下怎么办?办法就是仍然保留0x80号中断号,将其处理程序设置成ia32_syscall,它在ia32_sys_call_table中找具体的系统调用处理函数,具体在arch/x86_64/ia32/ia32entry.S中:

ENTRY(ia32_syscall)

CFI_STARTPROC

swapgs

sti

movl %eax,%eax

pushq %rax

cld

SAVE_ARGS 0,0,1

GET_THREAD_INFO(%r10)

testl $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),threadinfo_flags(%r10)

jnz ia32_tracesys

ia32_do_syscall:

cmpl $(IA32_NR_syscalls),%eax

jae  ia32_badsys

IA32_ARG_FIXUP

call *ia32_sys_call_table(,%rax,8) # xxx: rip relative

...

ia32_sys_call_table:

.quad sys_restart_syscall

.quad sys_exit

.quad stub32_fork

.quad sys_read

...

.quad compat_sys_ioctl

...

在arch/x86_64/kernel/traps.c的trap_init函数中将ia32_syscall设置成0x80号中断的处理程序:

set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);//#define IA32_SYSCALL_VECTOR 0x80

那么使用sysenter的怎么办呢? 这是通过在exec的时候由内核检测到其是32位程序是动态将处理代码map到gate处的,要知道x86-64也不使用sysenter机制进行系统调用。那64位的x86-64怎么系统调用呢?在arch/x86-64/kernel/entry.S中有ENTRY(system_call)这个标志,在arch/x86_64/kernel/setup64.c中的syscall_init函数中有以下一行:

wrmsrl(MSR_LSTAR, system_call);

可见64位的x86-64是通过一个MSR寄存器来保存系统调用处理地址的,而不再是通过中断。至于说机器如何处理这个信息以及这个寄存器如何影响系统运行,这已经到x86-64体系的cpu实现硬件问题了,和本文的linux系统的要旨无关,此处简略(再说不简略也不行啊,我也不会啊)。

3.总结

由于硬件指令的兼容,32位的程序在用户态不受任何影响的运行,由于内核保留了0x80号中断作为32位程序的系统调用服务,因此32位程序可以安全触发0x80号中断使用系统调用,由于内核为0x80中断安排了另一套全新的系统调用表,因此可以安全地转换数据类型成一致的64位类型,再加上应用级别提供了两套c库,可以使64位和32位程序链接不同的库。因此linux的64-32兼容搞得非常好。

为了看一下在x86-64上64位程序和32位程序是如何执行系统调用的,写一个最简单的测试程序:

#include

#include

int main()

{

getpid();

}

之所以选择getpid是因为它没有参数,最简单,将之在Red Hat 32位机器上按照如下命令行编译:

gcc test.c -o test-32 -g

然后再将之在64位机器上同样方式编译,只是可执行文件名字变为test-64。接下来首先gdb test-32:

(gdb) b main

...

(gdb) r

...

(gdb) b getpid

Breakpoint 2 at 0xf7f3d430

(gdb) disassemble  0xf7f3d430 0xf7f3d43a

0xf7f3d430 :  mov    $0x14,%eax    #0x14是20,正是getpid的系统调用号

0xf7f3d435 :  int    $0x80         #32位程序以int 0x80触发系统调用

0xf7f3d437 :  ret

0xf7f3d438 :  nop

0xf7f3d439 :  nop

End of assembler dump.

(gdb)

结果全部在,可见即使在64位机器上,32位程序仍然使用int 0x80触发系统调用,在内核中已经注册了0x80的中断处理函数。接下来再试一下64位的程序如何触发系统调用,执行gdb test-64:

(gdb) b main

...

(gdb) r

...

(gdb) b getpid

Breakpoint 2 at 0x32fbf90f40

(gdb) disassemble 0x32fbf90f40 0x32fbf90f70

Dump of assembler code from 0x32fbf90f40 to 0x32fbf90f70:

0x00000032fbf90f40 :  mov    %fs:0x94,%edx

0x00000032fbf90f48 :  test   %edx,%edx

0x00000032fbf90f4a : mov    %edx,%eax

0x00000032fbf90f4c : jle    0x32fbf90f50

0x00000032fbf90f4e : repz retq

0x00000032fbf90f50 : jne    0x32fbf90f5e

0x00000032fbf90f52 : mov    %fs:0x90,%eax

0x00000032fbf90f5a : test   %eax,%eax

0x00000032fbf90f5c : jne    0x32fbf90f4e

0x00000032fbf90f5e : mov    $0x27,%eax #系统调用号装入eax

0x00000032fbf90f63 : syscall         #执行系统调用

0x00000032fbf90f65 : test   %edx,%edx

0x00000032fbf90f67 : jne    0x32fbf90f4e

0x00000032fbf90f69 : mov    %eax,%fs:0x90

值得注意的是,在2.6.9内核的x86-64机器上,getpid和32位机器的getpid系统调用号有所不同,在64位上是39号,定义在include/asm-x86_64/unistd.h:

#define __NR_getpid                             39

__SYSCALL(__NR_getpid, sys_getpid)

而刚才看到过,32位兼容的getpid的系统调用号为20,定义在arch/x86_64/ia32/ia32entry.S中:

ia32_sys_call_table:

...

.quad sys_getpid                /* 20 */

...

PS:千万不要觉得test.c很简单然后就stepi单指令跟踪哦,因为这会涉及到一大堆跳转,如果你不明白链接的知识,不了解GOT和PIC的话,那就麻烦大了,因此还是直接在getpid处下断比较直观,如果你想顺便把代码重定位和GOT等玩意儿搞了的话,也可以试一下,反正在调试器面前,整个地址空间都会暴露,想看什么都行,当然,要学会让/proc//maps等文件帮忙哦。

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

标签:ia32,调用,x86,32,64,getpid,linux

来源: https://www.cnblogs.com/ksiwnhiwhs/p/10390736.html

linux 64位兼容32位,linux的64位操作系统对32位程序的兼容-全面分析相关推荐

  1. ios屏幕兼容 phone4和iphone5的屏幕尺寸不同,在程序中兼容

    自从iPhone4把屏幕分辨率提升了之后,苹果给开发者提供了一个point的概念,来取代旧的分辨率的概念.  它们假定屏幕上的定位和大小是用point来描述的,而iPhone3和iPhone4的屏幕是 ...

  2. 32位 shell.efi x86_通过grub,让32位的efi也能运行64位的Linux发行版

    GRUB是什么 是一个来自GNU项目的启动引导程序.GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统.GRUB可用于选择操作系统分区上的 ...

  3. Linux下的32位C程序,linux系统c语言生成.so文件,生成64位可执行文件,在64位系统中运行32位的可执行文件...

    1.linux 系统c语言生成.o文件,---->gcc -m64 -c -fPIC test.c -o test.o 2.linux 系统c语言生成.so文件,----->gcc -sh ...

  4. 查看系统架构是32位还是64位--用Enki学Linux系列(15)

    最简单的方式是执行: $ uname -m 这将输出 x86_64 或者 i386/i586/i686. 你可以使用-a参数获得更多内容: $ uname -a 32位系统的结果: Linux XXX ...

  5. 判断oracle客户端是32还是64,64位-如何知道已安装的Oracle Client是32位还是64位?

    64位-如何知道已安装的Oracle Client是32位还是64位? 操作系统:Windows 2008 Server R2 Oracle客户端:11.2 非常感谢 8个解决方案 73 votes ...

  6. 计算机二级安装64位的还是,电脑操作系统安装,该选择32位还是64位?

    编辑:晴晨 我们知道,电脑系统有32位和64位之分,每次安装系统前,不了解的人总会犹豫到底该安装哪个?如果选择错误,那么结果就会出现系统性能下降.不兼容.安装失败等问题.不都是系统吗,为何会这样?这要 ...

  7. Linux批量添加10个用户stu01,stu02....stu10,并设置8位随机密码

    批量创建10个用户stu01-stu10,并且设置随机8位密码,要求:不能用shell循环(例如:for,while等),只能用linux命令及管道实现. 此题考察的是基础命令的熟练运用,因此,限制了 ...

  8. Linux文件系统上的特殊权限      SUID, SGID, Sticky(粘之位)

    每个人都有自己的梦想,我想把它写出来. Linux文件系统上的特殊权限 SUID, SGID, Sticky(粘之位) 1 文件基本权限 r读, w写, x执行 user, group, other ...

  9. 内核知识第九讲,32位下的分页管理,36位下的分页管理.以及64位下的分页管理

    内核知识第九讲,32位下的分页管理,36位下的分页管理.以及64位下的分页管理 一丶熟悉WinDbg的常见命令. dd 虚拟地址      显示内存. !dd 加上!,        ! dd 物理地 ...

最新文章

  1. python 网页上显示数据_用Python实现网页数据抓取
  2. Linux下MySQL C API简单示例
  3. c轴 t轴 l轴_气涨轴-气胀轴
  4. IOS开发之小实例--UIImagePickerController
  5. 快速上手SpyGlass——CDC检查
  6. 认识Web.config文件
  7. python全栈学习--day8
  8. BZOJ1901:Zju2112 Dynamic Rankings——题解
  9. Eclipse右下角一直提示Computing additional info解决办法
  10. 82c55单片机c语言,AT89S51单片机与82C55的接口设计编程
  11. JDK1.8源码(十一)——java.util.TreeMap类
  12. 【图像重建】基于matlab GUI霍夫曼图像重建(带面板)【含Matlab源码 1168期】
  13. 计算机组成原理 王道考研2021 第一章:计算机组成原理概述 -- 本章小结、常见问题和易混淆知识点
  14. 那些我们卖掉的二手iPhone到底去哪了?
  15. 2013计算机学科排名,2013年世界大学学科排名 计算机科学.pdf
  16. Reverse complement DNA
  17. Linux下 vim的基本配置
  18. 2017-2018 ACM-ICPC, Asia Daejeon Regional Contest:Gym 101667K
  19. 如何利用PDF格式转换器在手机上完成PDF格式转换
  20. 来篇鸡汤文吧,教你如何七周内从小菜鸟成长为一名合格的数据分析师

热门文章

  1. leetcode刷题 60 61
  2. pytorch 常用层(四)
  3. 爬虫篇 | 快速入门selenium(十一)
  4. 你可能不需要固定词表:一种与词表无关的组合式词向量方法
  5. Self-Attention GAN 中的 self-attention 机制
  6. 风变python小课 基础语法12 作业1_菜鸟的风变编程Python小课之路,这么学编程也可以?...
  7. Module not found: Error: Can‘t resolve ‘sass-loader‘ in E:\IdeaProject\xinguan\xinguan
  8. python生成随机数代码_Python中产生随机数
  9. 安卓 java编译_Android源码分析(七)-----如何解决java编译版本问题
  10. Docker-操作容器1