在x86-32汇编中,参数存储在堆栈中,但在x86-64中,参数存储在寄存器中.这是什么原因?
据我所知,调用约定取决于平台是Windows还是Linux。
我想知道,
哪一个是真的?如果只有 2 为真,则调用约定是由平台定义的,编译器是否只遵循定义的约定?
我正在尝试学习一些汇编代码,并且正在遵循一本书提出的教程,我的 C++ 代码定义如下(Ch02_01.cpp):
#include <iostream>
using namespace std;
extern "C" int IntegerAddSub_(int a, int b, int c, int d);
int main() {
int a, b, c, d, result;
a = 101; b = 34; c = -190; d = 25;
result = IntegerAddSub_(a, b, c, d);
cout << "result = " << result << n1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
知道函数 IntegerAddSub_ 是在文件夹中的汇编文件(扩展名为 asm)中定义的,如下(Ch02_01.asm):
; extern "C" int IntegerAddSub_(int a, int b, int c, int d);
.code
IntegerAddSub_ proc
; Calculate a …Run Code Online (Sandbox Code Playgroud) 我写了一个函数来漂亮地打印一个数独,当然这个模式可以由一些循环生成,但我不想经历麻烦,所以这就是我想出的(前 5 个格式说明符只是参数) printf 本身被压入堆栈,并且在回车后将被覆盖)。
\n虽然“它可以在我的机器上运行”,但我想知道这是否可以或可以移植到跨架构、编译器、libc 实现等工作?
\n当然,根据目标平台,汇编代码可能需要进行一些调整,并且 printf 推送的参数数量取决于当前的 libc 实现。
\n#define PUSH(x) asm volatile ("push %0" : : "m"(x) :)\n#define POP() asm volatile ("pop %%rax" : : : "rax")\n\nvoid print(void) {\n for (uint8_t i = 1; i <= (9 * 9); ++i) {\n PUSH(sudoku[(9 * 9) - i]);\n }\n\n printf("%hhd%hhd%hhd%hhd%hhd\\r\xe2\x95\x94\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa6\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\xa6\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x90\xe2\x95\x97\\n"\n "\xe2\x95\x91 %hhd %hhd %hhd \xe2\x95\x91 %hhd %hhd %hhd \xe2\x95\x91 %hhd %hhd %hhd \xe2\x95\x91\\n"\n "\xe2\x95\x91 %hhd %hhd %hhd \xe2\x95\x91 %hhd %hhd %hhd \xe2\x95\x91 %hhd %hhd %hhd …Run Code Online (Sandbox Code Playgroud) 我目前正在通过反汇编C程序并试图了解它们的作用来进行汇编阅读.
我被困在一个简单的问题:一个简单的你好世界计划.
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("Hello, world!");
return(0);
}
Run Code Online (Sandbox Code Playgroud)
当我拆卸主要时:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400526 <+0>: push rbp
0x0000000000400527 <+1>: mov rbp,rsp
0x000000000040052a <+4>: mov edi,0x4005c4
0x000000000040052f <+9>: mov eax,0x0
0x0000000000400534 <+14>: call 0x400400 <printf@plt>
0x0000000000400539 <+19>: mov eax,0x0
0x000000000040053e <+24>: pop rbp
0x000000000040053f <+25>: ret
Run Code Online (Sandbox Code Playgroud)
我理解前两行:基本指针保存在堆栈上(通过push rbp,这会导致堆栈指针的值减少8,因为它已经"增长")并且堆栈指针的值被保存在基指针中(这样,参数和局部变量可以分别通过正偏移和负偏移轻松到达,而堆栈可以保持"增长").
第三行提出了第一个问题:为什么0x4005c4("Hello,World!"字符串的地址)在edi寄存器中移动而不是在堆栈中移动?printf函数不应该将该字符串的地址作为参数吗?据我所知,函数从堆栈中获取参数(但在这里,看起来参数放在该寄存器中:edi)
在StackOverflow上的另一篇文章中,我读到"printf @ ptl"就像一个调用真正的printf函数的存根函数.我试图反汇编这个功能,但它变得更加混乱:
(gdb) disassemble printf
Dump of assembler code for function __printf:
0x00007ffff7a637b0 <+0>: sub rsp,0xd8
0x00007ffff7a637b7 <+7>: test al,al …Run Code Online (Sandbox Code Playgroud) 我正在组装中构建一个32位操作系统.
我已经设置了IDT,我正在通过int指令处理程序interruptus .
如何启用syscall和sysenter说明以及如何处理/返回?
诚然,syscall指令在32位基于英特尔处理器的支持,所以我不能用它?sysret教学不安全是真的吗?在某处存在一个教程吗?
编辑:我的主要问题是如何启用syscall和sysenter说明!(没有重复)
assembly system-calls protected-mode osdev interrupt-handling
为什么32位C将所有函数参数直接推送到堆栈上,而64位C将前6个参数放入寄存器而其余的放在堆栈中?
所以32位堆栈看起来像:
...
arg2
arg1
return address
old %rbp
Run Code Online (Sandbox Code Playgroud)
虽然64位堆栈看起来像:
...
arg8
arg7
return address
old %rbp
arg6
arg5
arg4
arg3
arg2
arg1
Run Code Online (Sandbox Code Playgroud)
那么为什么64位C会这样做呢?将所有内容都推送到堆栈而不是将前6个参数放在寄存器中以便将它们移动到函数序言中的堆栈中是不是更容易?
在我迄今为止学到的关于分割的内容中:
所以,我的问题是:
基于我所读到的内容,虚拟地址被加载到段寄存器中,然后以某种方式从那里继续转换.在将虚拟地址加载到其中以获取描述符后,段寄存器会发生什么?
据我了解,段寄存器还包含描述符的缓存值.这在翻译过程中如何发挥作用?
系统如何确定要加载哪个段寄存器,假设段选择器最多可以有2 ^ 13个不同的值且只有6个主寄存器?
我正在用汇编语言编写用于冒泡排序的冒泡排序,并且正在使用strtok()对字符串进行标记化。但是,在第一次调用strtok(str,“”)之后,我需要将NULL作为参数传递,即strtok(NULL,“”)
我已经在.bss段中尝试了NULL equ 0,但这没有任何作用。
[SECTION .data]
[SECTION .bss]
string resb 64
NULL equ 0
[SECTION .text]
extern fscanf
extern stdin
extern strtok
global main
main:
push ebp ; Set up stack frame for debugger
mov ebp,esp
push ebx ; Program must preserve ebp, ebx, esi, & edi
push esi
push edi
push cadena
push frmt
push dword [stdin] ;Read string from stdin
call fscanf
add esp,12 ;clean stack
push delim
push string ;this works
call strtok
add esp,8 ;clean stack …Run Code Online (Sandbox Code Playgroud)