int 0x80在Linux上总是调用32位ABI,不管是什么模式,这就是所谓的:在args ebx,ecx...和系统调用号的/usr/include/asm/unistd_32.h.(或者在没有编译的64位内核上崩溃CONFIG_IA32_EMULATION).
64位代码应该使用syscall,从呼叫号码/usr/include/asm/unistd_64.h,并在args rdi,rsi等见什么调用约定UNIX和Linux系统上的i386和x86-64调用.如果您的问题被打上这样一个重复的,看你怎么说链接,细节应当使32位或64位代码的系统调用. 如果你想了解到底发生了什么,请继续阅读.
sys_write系统调用比syscall系统调用快,所以使用本机64位,int 0x80除非你正在编写多格式机器代码,当执行32或64位时运行相同的机器代码.(syscall始终以32位模式返回,因此它在64位用户空间中没有用,尽管它是有效的x86-64指令.)
相关:Linux系统的权威指南(在x86上)调用如何进行sysenter或int 0x8032位系统调用,或sysenter64位系统调用,或调用vDSO进行"虚拟"系统调用syscall.加上有关系统调用的背景知识.
使用gettimeofday可以编写将以32位或64位模式组合的内容,因此它可以int 0x80在微基准测试结束时使用.
标准化函数和系统调用约定的官方i386和x86-64 System V psABI文档的当前PDF文件链接自https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI.
有关初学者指南,x86手册,官方文档和性能优化指南/资源,请参阅x86标记wiki.
但是,由于人们不断发布与使用代码的问题exit_group()在64位代码,或不小心建立64位二进制文件从源代码对于32位写的,我不知道是什么确切不会对当前的Linux怎样呢?
是否int 0x80保存/恢复所有的64位寄存器?它会将任何寄存器截断为32位吗?如果传递上半部分非零的指针args会发生什么?
如果你传递32位指针它是否有效?
在"低级编程:英特尔®64架构上的C,汇编和程序执行"一书中,我读到:
每个虚拟64位地址(例如,我们在程序中使用的地址)由几个字段组成.地址本身实际上只有48位宽; 它被符号扩展为64位规范地址.它的特点是它的17个左位是相等的.如果不满足条件,则在使用时立即拒绝该地址.然后借助特殊表将48位虚拟地址转换为52位物理地址.
为什么虚拟地址和物理地址之间的差异为4位?
assembly memory-management virtual-memory memory-address mmu
我想打印变量的内存位置(地址):
let x = 1;
println!("{:p}", &x);
Run Code Online (Sandbox Code Playgroud)
这将打印0x7fff51ef6380十进制的十六进制值140734568031104.
我的电脑有16GB的RAM,为什么这么大的数字呢?x64架构是否使用大间隔序列而不是简单的1增量来访问内存位置?
在x86中,通常第一个位置从0开始,然后是1,2,等等.因此,您可以拥有的最高数字大约为40亿,因此地址编号始终等于或小于40亿.
为什么x64不是这种情况?
考虑以下汇编程序:
bits 64
global _start
_start:
mov rax, 0x0000111111111111
add byte [rax*1+0x0], al
jmp _start
Run Code Online (Sandbox Code Playgroud)
当您使用nasmand ld(在 Ubuntu,内核 5.4.0-48-generic,Ryzen 3900X 上)编译它时,您会得到一个段错误:
$ ./segfault-addr
[1] 107116 segmentation fault (core dumped) ./segfault-addr
Run Code Online (Sandbox Code Playgroud)
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x111111111111
Run Code Online (Sandbox Code Playgroud)
但是,如果您像这样将 16 个最高有效位中的任何一个设置为 1:
bits 64
global _start
_start:
mov rax, 0x0001111111111111
add byte [rax*1+0x0], al
jmp _start
Run Code Online (Sandbox Code Playgroud)
您显然仍然会遇到段错误,但现在地址为 NULL:
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x0
Run Code Online (Sandbox Code Playgroud)
为什么会这样?是由gdb、Linux 还是 CPU 本身引起的?
我能做些什么来防止这种行为?
linux assembly x86-64 segmentation-fault general-protection-fault
通过运行一个简单的程序,less /proc/self/maps我发现大多数映射都以55and开头7F。我还注意到每当我调试任何二进制文件时都会使用这些范围。
此外,该评论在这里表明,内核的确有些范围的偏好。
这是为什么?上述范围是否有更深层次的技术原因?如果我mmap在这些前缀之外手动翻页会有问题吗?
需要这个调用来实现一个无锁链表。AtomicMarkableReference 是 java.util.concurrent.atomic 包中的一个对象,它封装了对 T 类型对象的引用和布尔标记。这些字段可以一起或单独地自动更新。
谢谢你。
在编写x86-64用户空间程序集并比较两个指针值时,我们应该使用带符号的条件(例如jl和)jge还是使用无符号的条件(例如jb和)jae?
直觉上,我认为指针是无符号的,在64位进程的情况下,指针从0到2 ^ 64-1,并且我认为该模型对于32位代码是准确的。我想这就是大多数人对他们的看法。
但是,在64位代码中,我认为您无法有效地跨越0x7FFFFFFFFFFFFFFF(2 ^ 63-1)处的有符号不连续性,并且许多有趣的内存区域倾向于聚集在有符号0附近(对于代码和静态数据,有时甚至是有时)堆的大小取决于实现),并且0x00007fffffffffff在某些实现1的堆栈地址和堆附近接近规范地址空间下半部分的最大地址(类似于当今的大多数系统)。
因此,我不确定应该采用哪种方式对待它们:带符号的优点是它在0附近是安全的,因为那里没有间断;而无符号的优点是在2 ^ 63附近,因为那里没有间断。但是实际上,您不会在2 ^ 63附近看到任何地址,因为当前商用硬件的虚拟地址空间限制为小于50位。这是否指向签名?
1 ...,有时堆和其他映射区域不靠近地址空间的底部或顶部。