拿一个短程序做为例,今天我在测试的时候,我想要做同样的事情,在开始执行我们刚学到的系统调用之前备份所有寄存器。所以我首先尝试了 pusha 和 popa 这个我在旧的 IA-32 Intel 架构软件开发手册中找到的方法。然而它并没有起作用。我已经手动测试过这个方法是可行的,但是出现了一些问题。
#Author: Jonathan Lee
#Professor: Devin Cook
#CSC35
#4-27-23
#practicesyscall.asm
.intel_syntax noprefix
.data
Message:
.asciz "Learning about system calls.\n"
.text
.global _start
_start:
pusha #facilitates saving the current general purpose registers only 32 bit processor
mov rax, 1
mov rdi, 1
lea rsi, Message
mov rdx, 30
syscall
popa #facilitates restoring the registers only 32 bit processor
mov rax, 60
mov rdi, 0
syscall
当使用x64编译时,这是结果:
practicesyscall.asm: Assembler messages:
practicesyscall.asm:19: Error: `pusha' is not supported in 64-bit mode
practicesyscall.asm:25: Error: `popa' is not supported in 64-bit mode
没有 pusha 和 popa 助记符,它可以工作,这是结果:
Learning about system calls.
这将适用于x32模式:
Intel Ref Document
但是,如果您想尝试此方法,它也可以手动工作。
#Jonathan Lee
#CSC35
#Professor Cook
#3-31-23
#Practice NON credit assignment
.intel_syntax noprefix
.data
Intro:
.ascii "Hello world my name is Jonathan Lee\n\n SAC STATE STINGERS UP\n\n"
.ascii "This program is to aid in learning more about stacks inside of assembly language.\n"
.ascii "Register RSP is used to point to the top of the stack. If you use (push) it will load the stack and move the pointer (RSP) automatically.\n"
.ascii "The stack counts down not up in assembly language.\n"
.ascii "This is the current RSP point prior to loading a stack or program run:---------------------> \0"
NewLine:
.ascii "\n\0"
StackLoad:
.ascii "Program will now load 1-14 into registers and push to the stack after it will write the register values and current RSP pointer value again.\n"
.ascii "This will not use registers RSP/RDI they are in use for stack pointer and class subroutines.\n\0"
ZeroLoad:
.ascii "Program will now load 0 into all registers and write register values after to show values are now stored in memory not registers.\n\0"
PopLoad:
.ascii "Note RSP is still using the same value. The program will now pop the stack and reverse load the values into the registers, after will write register values.\n"
.ascii "Last In First Out.\n\0"
RSPAddress:
.ascii "This is the current next available RSP Pointer Memory Address on top of stack:-------------> \0"
PostStack:
.ascii "This is the the current next available RSP Pointer Memory Address after stack is popped:---> \0"
PreExit:
.ascii "\nNote that the RSP is now pointing to the same memory address value as when the program started.\n\n\0"
.text
.global _start
_start:
call ClearScreen
lea rdi, NewLine
call WriteString
lea rdi, Intro
call WriteString
mov rdi, rsp
call WriteHex
lea rdi, NewLine
call WriteString
mov rax, 1
mov rbx, 2
mov rcx, 3
mov rdx, 4
mov rsi, 5
mov rdi, 6
mov rbp, 7
#rsp index use
mov r8, 8
mov r9, 9
mov r10, 10
mov r11, 11
mov r12, 12
mov r13, 13
mov r14, 14
mov r15, 15
lea rdi, StackLoad
call WriteString
push rax
push rbx
push rcx
push rdx
push rsi
push rbp
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
call WriteRegisters
lea rdi, RSPAddress
call WriteString
mov rdi, rsp
call WriteHex
lea rdi, NewLine
call WriteString
lea rdi, ZeroLoad
call WriteString
mov rax, 0
mov rbx, 0
mov rcx, 0
mov rdx, 0
mov rsi, 0
mov rbp, 0
mov r8, 0
mov r9, 0
mov r10, 0
mov r11, 0
mov r12, 0
mov r13, 0
mov r14, 0
mov r15, 0
call WriteRegisterslea rdi, RSPAddress
call WriteString
mov rdi, rsp
call WriteHex
lea rdi, NewLine
call WriteString
lea rdi, PopLoad
call WriteString
pop rax
pop rbx #Last In First Out
pop rcx
pop rdx
pop rsi
pop rbp
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14#flip stack
pop r15
call WriteRegisters
lea rdi, PostStack
call WriteString
mov rdi, rsp
call WriteHex
lea rdi, NewLine
call WriteString
lea rdi, PreExit
call WriteString
call Exit
结果将会是:
Hello world my name is Jonathan Lee
SAC STATE STINGERS UP
This program is to aid in learning more about stacks inside of assembly language.
Register RSP is used to point to the top of the stack. If you use (push) it will load the stack and move the pointer (RSP) automatically.
The stack counts down not up in assembly language.
This is the current RSP point prior to loading a stack or program run:---------------------> 00007FFEC3675420
Program will now load 1-14 into registers and push to the stack after it will write the register values and current RSP pointer value again.
This will not use registers RSP/RDI they are in use for stack pointer and class subroutines.
RAX : 0000000000000001 R8 : 0000000000000008
RBX : 0000000000000002 R9 : 0000000000000009
RCX : 0000000000000003 R10 : 000000000000000A
RDX : 0000000000000004 R11 : 000000000000000B
RDI : 0000000000600AA5 R12 : 000000000000000C
RSI : 0000000000000005 R13 : 000000000000000D
RBP : 0000000000000007 R14 : 000000000000000E
RSP : 00007FFEC36753A0 R15 : 000000000000000F
This is the current next available RSP Pointer Memory Address on top of stack:-------------> 00007FFEC36753B0
Program will now load 0 into all registers and write register values after to show values are now stored in memory not registers.
RAX : 0000000000000000 R8 : 0000000000000000
RBX : 0000000000000000 R9 : 0000000000000000
RCX : 0000000000000000 R10 : 0000000000000000
RDX : 0000000000000000 R11 : 0000000000000000
RDI : 0000000000600B90 R12 : 0000000000000000
RSI : 0000000000000000 R13 : 0000000000000000
RBP : 0000000000000000 R14 : 0000000000000000
RSP : 00007FFEC36753A0 R15 : 0000000000000000
This is the current next available RSP Pointer Memory Address on top of stack:-------------> 00007FFEC36753B0
Note RSP is still using the same value. The program will now pop the stack and reverse load the values into the registers, after will write register values.
Last In First Out.
RAX : 000000000000000F R8 : 0000000000000009
RBX : 000000000000000E R9 : 0000000000000008
RCX : 000000000000000D R10 : 0000000000000007
RDX : 000000000000000C R11 : 0000000000000005
RDI : 0000000000600C13 R12 : 0000000000000004
RSI : 000000000000000B R13 : 0000000000000003
RBP : 000000000000000A R14 : 0000000000000002
RSP : 00007FFEC3675410 R15 : 0000000000000001
This is the the current next available RSP Pointer Memory Address after stack is popped:---> 00007FFEC3675420
Note that the RSP is now pointing to the same memory address value as when the program started.
长话短说,您可以手动将寄存器逐个加载到堆栈中,并在需要时弹出它们以恢复它。
pusha
编写新的微码。有趣的是,AMD k7和k8在32位模式下的pusha
速度是8个连续的push
指令的两倍(每4个时钟周期一个,根据Agner Fog的测试:https://agner.org/optimize/),因此显然它一次存储一对32位寄存器以绕过每个时钟周期1个存储的瓶颈。在英特尔上,它不值得用于性能,只用于代码大小(Merom上的8c吞吐量,18个uops,Intel的第一个64位P6微架构)。 - Peter Cordes