我知道在Arm汇编中我们可以使用如下移位操作数:
mov r0, r1, lsl #2
我使用gcc来编译,因此我必须调整语法。
我已经尝试过这个:
mov w0, w1, lsl 2
它不起作用:unexpected characters following instruction at operand 2
。对我来说,它说它无法处理第三个操作数。
在 gnu 中是否有其他语法可以完成同样的工作?
我知道在Arm汇编中我们可以使用如下移位操作数:
mov r0, r1, lsl #2
我使用gcc来编译,因此我必须调整语法。
我已经尝试过这个:
mov w0, w1, lsl 2
它不起作用:unexpected characters following instruction at operand 2
。对我来说,它说它无法处理第三个操作数。
在 gnu 中是否有其他语法可以完成同样的工作?
在这一点上,我感到非常迷茫,这就是为什么我的代码看起来像这样
org 100h
start:
xor ax, ax
xor dx, dx
mov ah, 1
xor cx, cx
input:
int 21h
cmp al, '+'
jz sum
push ax
inc cx
jmp input
sum:
push bp
mov bp, sp
mov cx, [bp+4]
mov si, 6
xor ax, ax
sum_loop:
push bp
mov bp, sp
mov ax, [bp+6]
mov bx, [bp + 4]
add ax, bx
mov [result], ax
pop ax
loop sum_loop
pop bp;
ret
print:
mov al, [result]
mov bl, 10
div bl
mov [pt_one], ah
xor ah, ah
div bl
mov [pt_two], ah
xor ah, ah
add al, 48
mov dl, al
mov ah, 2
int 21h
mov al, [pt_two]
add al, 48
mov dl, al
mov ah, 2
int 21h
xor al, al
mov al, [pt_one]
add al, 48
mov dl, al
mov ah, 2
int 21h
mov ax, 4c00h
int 21h
section .data
pt_one db 1
pt_two db 1
result db 0
在这里,我确信输入部分可以正常工作,但我不知道是我的求和协议有问题还是我的打印方式有问题。求和时,我尝试添加 2 个下一个元素并将其添加到结果变量中,然后删除堆栈顶部。当我尝试此代码(通常我输入 123+)并输入 + 时,什么也没发生,老实说,我不知道如何修复它。
我试图了解当 RPQ(读取待处理队列)和 WPQ(写入待处理队列)之间存在显著的队列压力差异时,内存控制器如何在非临时负载和非临时存储之间维持程序顺序。
考虑以下序列:
load A // goes to RPQ
ntstore A // goes to WPQ
如果 RPQ 有许多待处理的条目(比如 20 个)并且 WPQ 相对空(比如 2 个条目),直观地看似乎存储在加载完成之前就可以到达 DRAM:
我编写了一个测试程序(见下文)来验证这个假设。其中:
核心测试序列:
uint64_t val = MAGIC_A;
uint64_t addr = (uint64_t)&memory[test_idx].sentinel;
asm volatile(
"mov (%1), %%rax\n\t" // Load into rax
"movnti %%rbx, (%1)\n\t" // NT Store
"mov %%rax, %0\n\t" // Save loaded value
: "=r"(val)
: "r"(addr), "b"(MAGIC_B)
: "rax", "memory"
);
if (val == MAGIC_B) { // Would indicate store completed before load
local_violations++;
}
结果:以 16 个线程和每个线程 10M 缓存行运行,我们发现 0 个违规。性能计数器确认我们达到了所需的队列压力:
$ sudo perf stat -e uncore_imc_0/unc_m_rpq_occupancy/ -e uncore_imc_0/unc_m_rpq_inserts/ -e uncore_imc_0/unc_m_wpq_occupancy/ -e uncore_imc_0/unc_m_wpq_inserts/ -e uncore_imc_3/unc_m_rpq_occupancy/ -e uncore_imc_3/unc_m_rpq_inserts/ -e uncore_imc_3/unc_m_wpq_occupancy/ -e uncore_imc_3/unc_m_wpq_inserts/ sleep 60
[sudo] password for vin:
Performance counter stats for 'system wide':
2,893,410,795,007 uncore_imc_0/unc_m_rpq_occupancy/
9,443,033,953 uncore_imc_0/unc_m_rpq_inserts/
574,954,888,344 uncore_imc_0/unc_m_wpq_occupancy/
32,101,285 uncore_imc_0/unc_m_wpq_inserts/
1,086,622,871 uncore_imc_3/unc_m_rpq_occupancy/
38,269,189 uncore_imc_3/unc_m_rpq_inserts/
76,056,378,805 uncore_imc_3/unc_m_wpq_occupancy/
31,895,245 uncore_imc_3/unc_m_wpq_inserts/
60.002128565 seconds time elapsed
在这种情况下,内存控制器如何维持程序顺序?鉴于队列深度存在显著差异(RPQ ~306 vs WPQ ~18),哪些机制可以防止存储在其先前的加载之前完成?我怀疑除了简单的队列动态之外还存在某种排序机制,但我不明白它是什么。
以下是完整的代码: https: //gist.github.com/VinayBanakar/6841e553d274fa5b8a156c13937405c8
以下函数,
#include <string.h>
void func1(char *s)
{
char buffer[4];
strcpy(buffer, s);
}
已编译,
$ arm-linux-gnueabi-gcc -g -fno-stack-protector func1.c -c -o func1.o
$ arm-linux-gnueabi-gcc --version
arm-linux-gnueabi-gcc (Ubuntu 13.2.0-4ubuntu3) 13.2.0
并拆卸:
$ arm-linux-gnueabi-objdump --disassemble=func1 -S func1.o
void func1(char *s)
{
0: e92d4800 push {fp, lr}
4: e28db004 add fp, sp, #4
8: e24dd010 sub sp, sp, #16
c: e50b0010 str r0, [fp, #-16]
char buffer[4];
strcpy(buffer, s);
10: e24b3008 sub r3, fp, #8
14: e51b1010 ldr r1, [fp, #-16]
18: e1a00003 mov r0, r3
1c: ebfffffe bl 0 <strcpy>
}
20: e1a00000 nop @ (mov r0, r0)
24: e24bd004 sub sp, fp, #4
28: e8bd8800 pop {fp, pc}
我的分析strcpy()
:调用(指令)之后0x20
堆栈有以下内容:
|---+---+---+---|
fp - 20 | ????????? | <- current $sp
|---+---+---+---|
fp - 16 | char * s | <- $r1
|---+---+---+---|
fp - 12 | ????????? |
|---+---+---+---|
fp - 8 | char buffer[] | <- $r0, $r3
|---+---+---+---|
fp - 4 | prev $fp | <- $sp after push
|---+---+---+---|
| $lr | <- $fp
|---+---+---+---|
| | | | | <- $sp that had the calling function
|---+---+---+---|
.
.
.
^
| descending addresses
问题:
$sp
指向的内容是什么?由于 ARM 使用完整的降序堆栈,因此该元素被标记为已占用,并且被调用的函数不会使用该空间。AVR 有ADC
(带进位加法) 和ROL
(带进位左移) 指令。
然而,在我看来,这ROL
完全没有必要,而且ADC r, r
目的相同。
据我所知,ADC r, r
和的ROL r
结果都是(r << 1) | carry
。对于两者,进位都设置为操作数的MSB。
以下是一个例子:
r = 0x12 = 0001_0010
,carry = 0
ADC r, r
r = 0010_0100 = 0x24
carry = 0
ROL r
r = 0010_0100 = 0x24
carry = 0
直观地讲,将寄存器加到自身就是将其乘以二,这与左移一相同。ADC
同时还添加了进位,这成为结果的新 LSB。
那么 even 是什么意思呢?和ROL
之间有语义差异吗?我相信和也
可以得到同样的结论。ROL r
ADC r, r
ROR
SBC
我正在编写一个 16 位 x86 汇编操作系统,并且正在开发程序执行。我设计的执行有所不同,因为我希望内核执行代码(这样它就可以更好地控制程序要做什么,因此如果它想覆盖驱动器 A:用户会得到通知),而不是 CPU。所以我正在编写一个文件,exec.asm
其中包含将读取程序并执行相应指令的函数。在解释我的问题之前,我会给你留下源代码。
下载文件
DLOAD:
PUSHA
MOV AH, 0X02
MOV AL, 0X04
MOV CH, 0X00
MOV CL, 0X02
MOV DH, 0X00
MOV DL, BL
MOV BX, 0X0000
MOV ES, BX
MOV BX, 0X7E00
INT 0X13
JC DERRR
DSUCC:
POPA
MOV AL, 0X00
RET
DERRR:
POPA
MOV AL, 0X01
RET
打印.asm
PRINT_CHR:
PUSHA
MOV AH, 0X0E
MOV AL, [BX]
INT 0X10
POPA
RET
PRINT_STR:
PUSHA
MOV AH, 0X0E
PRINT_STR_LOOP:
MOV AL, [BX]
CMP AL, 0X00
JE END_PRINT_STR
INT 0X10
INC BX
JMP PRINT_STR_LOOP
END_PRINT_STR:
POPA
RET
屏幕文件
SHOW_BASIC_SCREEN:
PUSHA
MOV AH, 0X0E
MOV BX, PNAME_OFFSET
MOV CX, 0X14
SHOW_PNAME:
MOV AL, [BX]
CMP CX, 0X00
JE SHOW_PNAME_END
INT 0X10
INC BX
DEC CX
JMP SHOW_PNAME
SHOW_PNAME_END:
MOV AL, '='
INT 0X10
INT 0X10
MOV CX, 0X12
AFTER_PNAME_SPACES:
MOV AL, ' '
CMP CX, 0X00
JE END_SPACING
INT 0X10
DEC CX
JMP AFTER_PNAME_SPACES
END_SPACING:
MOV AL, '='
INT 0X10
INT 0X10
MOV AL, ' '
INT 0X10
MOV AL, '}'
INT 0X10
MOV CX, 0X24
SHOW_INPUT_SPACE:
MOV AL, ' '
CMP CX, 0X00
JE END_INPUT_SPACE
INT 0X10
DEC CX
JMP SHOW_INPUT_SPACE
END_INPUT_SPACE:
MOV CX, 0X16
CLOSE_PNAME:
MOV AL, '='
CMP CX, 0X00
JE CLOSE_PNAME_END
INT 0X10
INC BX
DEC CX
JMP CLOSE_PNAME
CLOSE_PNAME_END:
MOV CX, 0X12
CLOSE_SPACES:
MOV AL, ' '
CMP CX, 0X00
JE CLOSE_SPACES_END
INT 0X10
DEC CX
JMP CLOSE_SPACES
CLOSE_SPACES_END:
MOV CX, 0X28
CLOSE_INPUT:
MOV AL, '='
CMP CX, 0X00
JE CLOSE_INPUT_END
INT 0X10
DEC CX
JMP CLOSE_INPUT
CLOSE_INPUT_END:
POPA
RET
PNAME_OFFSET EQU 0X9000
汇编语言
_SETC:
MOV AH, 0X02
MOV AL, 0X00
MOV BH, 0X00
INT 0X10
RET
汇编语言
CSCR:
PUSHA
MOV CX, BX
MOV AH, 0X0E
CSCR_LOOP:
MOV AL, 0X0A
CMP CX, 0X00
JE CSCR_END
INT 0X10
DEC CX
JMP CSCR_LOOP
CSCR_END:
MOV AH, 0X02
MOV BH, 0X00
MOV DH, 0X00
MOV DL, 0X00
INT 0X10
POPA
RET
执行汇编
EXEC_INC:
INC BX
EXEC:
PUSHA
MOV BX, 0X02
CALL CSCR
CALL SHOW_BASIC_SCREEN
POPA
MOV AL, [BX]
CMP AL, 0X00
JE _0X00
CMP AL, 0X50
JE _0X50
CMP AL, 0X51
JE _0X51
CMP AL, 0X49
JE _0X49
CMP AL, 0X4A
JE _0X4A
CMP AL, 0X3C
JE _0X3C
CMP AL, 0X52
JE _0X52
CMP AL, 0X53
JE _0X53
CMP AL, 0X3E
JE _0X3E
CMP AL, 0X7F
JE _0X7F
JMP EXEC_ERR
_0X50:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
POPA
INC BX
MOV AH, 0X0E
MOV AL, [BX]
INT 0X10
JMP EXEC_INC
_0X51:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
POPA
INC BX
MOV AH, 0X0E
_0X51_LOOP:
MOV AL, [BX]
CMP AL, 0X00
JE EXEC_INC
INT 0X10
INC BX
JMP _0X51_LOOP
_0X49:
PUSHA
MOV DH, 0X00
MOV DL, 0X2D
CALL _SETC
MOV AH, 0X00
MOV BX, INPUT_ADDR
INT 0X16
MOV [BX], BYTE AL
POPA
JMP EXEC_INC
_0X4A:
PUSHA
MOV DH, 0X00
MOV DL, 0X2D
CALL _SETC
MOV BX, INPUT_ADDR
_0X4A_LOOP:
MOV AH, 0X00
INT 0X16
CMP AL, 0XD
JE _0X4A_END
CMP AL, 0X7F
JE _0X4A_DEL
MOV [BX], BYTE AL
MOV AH, 0X0E
INT 0X10
INC BX
JMP _0X4A_LOOP
_0X4A_DEL:
DEC BX
MOV [BX], BYTE 0X00
JMP _0X4A_LOOP
_0X4A_END:
MOV [BX], BYTE 0X00
POPA
JMP EXEC_INC
_0X3C:
INC BX
MOV AH, [BX]
INC BX
MOV AL, [BX]
PUSHA
MOV BX, PADDR
MOV [BX], BYTE AH
INC BX
MOV [BX], BYTE AL
POPA
JMP EXEC_INC
_0X52:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
MOV BX, PADDR
MOV AH, [BX]
INC BX
MOV AL, [BX]
MOV BX, AX
MOV AH, 0X0E
MOV AL, [BX]
INT 0X10
POPA
JMP EXEC_INC
_0X53:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
MOV BX, PADDR
MOV AH, [BX]
INC BX
MOV AL, [BX]
MOV BX, AX
MOV AH, 0X0E
_0X53_LOOP:
MOV AL, [BX]
CMP AL, 0X00
JE _0X53_END
INT 0X10
INC BX
JMP _0X53_LOOP
_0X53_END:
POPA
JMP EXEC_INC
_0X3E:
MOV BX, PADDR
MOV AH, [BX]
INC BX
MOV AL, [BX]
MOV BX, AX
ADD BX, 0X9000
JMP EXEC
_0X7F:
PUSHA
MOV DH, 0X00
MOV DL, 0X00
CALL _SETC
MOV BX, 0X19
CALL CSCR
POPA
JMP EXEC_INC
_0X00:
RET
EXEC_ERR:
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
MOV BX, EXEC_ERR_MSG
CALL PRINT_STR
EXEC_ERR_MSG:
DB "Error executing program.", 0X0A, 0X0D, "Unrecognized instruction code.", 0X0A, 0X0D, 0X00
PADDR EQU 0X8C00
启动文件
[ORG 0X7C00]
MOV BP, 0XF000
MOV SP, BP
__MAIN:
MOV BX, DSKL_MSG
CALL PRINT_STR
MOV BL, DL
CALL DLOAD
CMP AL, 0X01
JE __ERR
MOV BX, DONE_DSKL_MSG
CALL PRINT_STR
MOV BX, KSTART_MSG
CALL PRINT_STR
JMP KOFFSET
__ERR:
MOV BX, ERRR_DSKL_MSG
CALL PRINT_STR
JMP __END
DSKL_MSG:
DB "Loading disk at 0x0000:0x7e00...", 0X0A, 0X0D, 0X00
DONE_DSKL_MSG:
DB "Disk loaded successfully at 0x0000:0x7e00.", 0X0A, 0X0D, 0X00
ERRR_DSKL_MSG:
DB "Fatal: unable to read disk. Cannot load kernel and boot the system.", 10, 13, 0
KSTART_MSG:
DB "Starting kernel... ", 0X0A, 0X0D, 0X00
KOFFSET EQU 0X7E00
%INCLUDE "print.asm"
%INCLUDE "dload.asm"
__END:
JMP $
TIMES 510 - ( $ - $$ ) DB 0X0
DW 0XAA55
内核汇编
[ORG 0X7E00]
__KSTART:
MOV BX, KSTARTED_MSG
CALL PRINT_STR
MOV BX, 25
CALL CSCR
__MAIN:
MOV BX, 0X02
CALL CSCR
MOV [0X9000], BYTE 'P'
MOV [0X9001], BYTE 'A'
MOV [0X9002], BYTE 'R'
MOV [0X9003], BYTE 'R'
MOV [0X9004], BYTE 'O'
MOV [0X9005], BYTE 'T'
MOV [0X9006], BYTE ' '
MOV [0X9007], BYTE ' '
MOV [0X9008], BYTE ' '
MOV [0X9009], BYTE ' '
MOV [0X900A], BYTE ' '
MOV [0X900B], BYTE ' '
MOV [0X900C], BYTE ' '
MOV [0X900D], BYTE ' '
MOV [0X900E], BYTE ' '
MOV [0X901F], BYTE ' '
MOV [0X9010], BYTE ' '
MOV [0X9011], BYTE ' '
MOV [0X9012], BYTE ' '
MOV [0X9013], BYTE ' '
MOV [0X9014], BYTE 0X4A
MOV [0X9015], BYTE 0X3C
MOV [0X9016], BYTE 0X8A
MOV [0X9017], BYTE 0X00
MOV [0X9018], BYTE 0X53
MOV [0X9019], BYTE 0X7F
MOV [0X901A], BYTE 0X3C
MOV [0X901B], BYTE 0X00
MOV [0X901C], BYTE 0X14
MOV [0X901D], BYTE 0X3E
MOV [0X901E], BYTE 0X00
CALL SHOW_BASIC_SCREEN
MOV BX, 0X9014
CALL EXEC
KSTARTED_MSG:
DB "Kernel started successfully.", 0X0A, 0X0D, 0X00
INPUT_ADDR EQU 0X8A00
%INCLUDE "print.asm"
%INCLUDE "cscr.asm"
%INCLUDE "screen.asm"
%INCLUDE "setc.asm"
%INCLUDE "exec.asm"
JMP $
EXEC 正在运行位于 0x9014 的程序。
今天我在文件中写入了 0X7F 指令(用于清除屏幕)exec.asm
。现在它可以工作了,但 0X50、0X51、0X52 和 0X53 指令中发生了一些变化(分别用于打印字符、打印字符串、BX 指向的字符和 BX 指向的以空字符结尾的字符串)。在这些指令的开头,您可以看到以下代码片段:
PUSHA
MOV DH, 0X03
MOV DL, 0X00
CALL _SETC
POPA
它用于将光标设置在屏幕的第 4 行,但由于某种原因,自从我添加了 0X7F 指令后,它就被绕过了。即使我在 DH(用于存储光标必须移动到的行的寄存器)中存储了一个大数字,如果调用打印函数,它会在第 3 行打印我的字符或字符串。
我使用 NASM 将boot.asm
和编译kernel.asm
为两个单独的文件boot.bin
和kernel.bin
,因此我将这两个文件复制到另一个文件中main.bin
(使用 Windows CMD 命令copy boot.bin/b+kernel.bin/b main.bin
),这是我使用 Bochs Emulator 2.8 启动的可启动文件。
我希望你能理解我的问题(如果你需要更多信息请告诉我,我会编辑帖子并添加必要的信息)!
当您在 x86 或 x86_64 中执行算术运算,并导致设置溢出标志或任何其他标志时,设置的位是否会影响运算结果值存储在哪个寄存器中?还是这只会发生在分支指令中?
我尝试自己测试一下,创建一个汇编文件,然后将其转换为可执行文件,并用 GDB 进行分析,但由于某种原因,它总是显示错误的架构,所以我决定直接来这里看看是否能得到直接的答案
我一直在尝试通读 ARM 手册,以了解 ARM 的架构工作原理。我知道每个 EL 都有一个用于 SP 的系统寄存器,如 SP_EL0、SP_EL1 等。我还知道 PSTATE 中有一个 SPSel 位,用于选择在 EL 更改时是否从 SP_EL0 或 SP_ELx 获取堆栈指针。但是,我的问题是,SP 是否在架构上映射到适当的 SP_ELx 寄存器,或者 SP_ELx 是否在 EL 更改时复制到 SP?换句话说,如果我写入 SP,我是否也会写入 SP_ELx?
我尝试阅读这方面的手册,但它看起来相当模糊,并且可以用任何一种方式来解释。
org 0x0100
jmp start
; Declare variables
input1: db 0
input2: db 7
input3: db 9
input4: db 1
message1: db 'The value of AX, BX and CX is: '
length: dw 31
start:
; Push output variables with random values
push 3 ; Random value 1
push 5 ; Random value 2
push 7 ; Random value 3
call my_subroutine
; Retrieve output variables
pop cx ; Retrieve output into CX
pop bx ; Retrieve output into BX
pop ax ; Retrieve output into AX
;Display the output values
call display
; Exit program
mov ax, 0x4c00
int 0x21
my_subroutine:
; Save registers
push ax
push bx
push si
push di
push cx
; Local variables (initialized with random values)
local1: dw 1
local2: dw 2
local3: dw 3
local4: dw 4
local5: dw 5
; Example operations (just random logic for demonstration)
mov ax, [input1] ; Load first input
add ax, [local1] ; Add local variable
mov bx, [input2] ; Load second input
sub bx, [local2] ; Subtract local variable
; Push results
;push ax ; Push first output (AX)
;push bx ; Push second output (BX)
;mov cx, word [input3]
;push cx ; Push third output (local variable)
; Restore registers
pop cx ; Pop last pushed value into CX
pop bx ; Restore BX
pop ax ; Restore AX
pop di ; Restore DI
pop si ; Restore SI
ret ; Return to the caller
cls:
push es
push ax
push di
mov ax, 0xB800
mov es, ax
mov di, 0
allSpace:
mov word [es:di], 0x0720
add di, 2
cmp di, 4000
jne allSpace
pop di
pop ax
pop es
ret
convert_num_to_string:
push bp
mov bp, sp
push es
pusha
mov ax, 0xb800
mov es, ax
mov ax, [bp+4]
mov bx, 10
mov cx, 0
nextdigit:
mov dx, 0
div bx
add dl, 0x30
push dx
inc cx
cmp ax, 0
jnz nextdigit
nextpos:
pop dx
mov dh, 0x07
mov [es:di], dx
add di, 2
loop nextpos
popa
pop es
pop bp
ret 2
display_message:
push bp
mov bp, sp
push es
push ax
push bx
push cx
mov ax, 0xb800
mov es, ax
mov si, [bp+6]
mov cx, [bp+4]
mov ah, 0x07
printAllChar:
mov al, [si]
mov [es:di], ax
add di, 2
add si, 1
loop printAllChar
pop cx
pop bx
pop ax
pop es
pop bp
ret 4
display:
call cls
mov di, 0
push message1
push word [length]
call display_message
mov di, 62
push ax
call convert_num_to_string
mov di, 66
push bx
call convert_num_to_string
mov di, 70
push cx
call convert_num_to_string
ret
my_subroutine:
在上面的子程序中,当我将结果推送到堆栈时,控制不会返回开始,而是运行无限循环
您需要用汇编语言编写一个子程序:
- 接受 4 个输入变量(即您的学号中的数字,即 22F-3440,3440 是 4 个输入)。
- 返回 3 个输出变量。这些输出变量(使用随机值)被推送到主函数中的输入变量之前。
- 在函数内部创建 5 个局部变量。使用 1 到 10 之间的随机值进行初始化。
- 使用寄存器 AX、BX、SI、DI 和 CX 执行运算,但在使用前后保存和恢复这些寄存器,以避免覆盖其原始值。
- 子程序返回后,必须将输出弹出到 AX、BX 和 CX 中。
- 将这些显示到控制台。
当您从 C/C++ 调用某个函数时,如果该函数的一些参数小于 64 位,运行时是否会将这些参数所在位置的堆栈内存清零?或者每个参数的顶部是否包含垃圾?
每个参数的空间为 8 个字节(64 位),但它们可能代表 8、16 或 32 位值。
假设参数不是通过寄存器传递的,因为这个问题涉及任何参数,而不仅仅是前 4 个。
void foobar(bool a, i32 b, float c, i64 d)
{
int x = 0, y = 0, z = 0;
}
----------------------------------------
# Stack Frame #
[... Previous StackFrame ...] // <HIGH ADDRESS>
[d]
[c]
[b] // Do the top 32 most-significan-bits of param 'b' contain garbage, or zero?
[a]
[ReturnAddr]
[Saved rbp]
[x]
[y]
[z]
// read 'b' value -- if the top 32bits of 'b' contains garbage, rax has wrong value.
mov rax, qword ptr[rbp+24]