64 位汇编编程基础 NASM 编程
Basics of Assembly programming in 64-bit NASM programming
我是汇编编程的新手,正在尝试解释以下代码,我必须在其中打印 .data 部分中存在的数组:
这是代码:
%macro print 2
mov rax,1
mov rdi,1
mov rsi,%1
mov rdx,%2
syscall
%endmacro
%macro exit 0
mov rax,60
mov rdi,0
syscall
%endmacro
section .data
msg db 10,"Array is : ",10
len equ $-msg
array dq 11234H, 0AB32H, -3326H, 056BH
newline db 10
section .bss
buff resb 16;
section .code
global _start
_start:
print msg,len
mov rsi,array
mov rcx,4
back:
mov rbx,[rsi]
push rsi
push rcx
call HextoASCII
print newline,1
pop rcx
pop rsi
add rsi,8
loop back
exit
HextoASCII:
mov rsi,buff
mov rcx,16
back1:
rol rbx,4
mov al,bl
and al,0fh
cmp al,9h
jbe add_30h
add al,7h
add_30h:
add al,30h
mov [rsi],al
inc rsi
loop back1
print buff,16
ret
有几个问题想请教解惑:
.bss 部分中存在的变量的默认值是多少?
msg 的大小是 10 个字节(msg 的最大大小),但是当我在其中输入更多字符时,即使字符串大小超过其最大限制,它仍然会打印整个 msg( 10 个字节).
如果数组中给出的数字最后(最高有效位)为非零,是否意味着该数字为负数
ie.- 数组中的 11234H 不是负数,因为我假设最高有效位在内存中显示为 1 (FFF11234H)。我认为对于一个非负数,它的最高位必须是零(011234),这样高阶位在内存中存储为 0 并使数字为正数。
如果我在这里错了,那么要问的另一件事是 FFFFFFFFH 是 -1 还是一个大的正数。
我对指令感到困惑
inc rsi
据说rsi加1。但是这里的1是什么,bit还是byte还是8byte(rsi的大小)。
添加 30H 或 37H 会将十六进制数字转换为 39H 或 41H,这些是 9 和 A 在 ASCII 中的十六进制表示,但我不明白为什么打印 39H 或 41H 会产生结果 9 或 A在我的显示器上,而不是 39H 或 41H 本身。是不是无论我们的结果是什么,汇编程序都会在监视器上打印出它的 ASCII 等价物。此外,我们通过 assembler/machine 解释的键盘输入是以什么形式提供的?如果它是 ASCII,那么我是否需要将其显式转换回 HEX 以供以后计算?
添加 30H 或 37H 后,单位数字(0H-9H 或 AH-FH)将转换为双位数,范围为 30H-39H 和 41H - 46H,因此当我们将其移动到buff,转换后实际上不会占用数组元素的两倍大小到buff中存储吗?我假设之前数字占用 4 位,现在转换后占用 8 位(9h 是 4 位,39h 是 8 位)。如果我在这里错了,请纠正我。
如果我是对的,这就是为什么当每个数组元素大小仅为 8 字节(四字)时 buff 被视为 16 字节的原因吗?
我理解 HextoASCII 的逻辑,它获取数字的最高位并将其存储在 buff 中,然后继续打印 buff 但不会以相反的方式打印数字,因为数组元素的最高位存储在 buff 的最低有效位置,并且随着 rsi 递增,下一个数字将添加到 buff 的较高位置,因此如果我们打印 buff,那么最高有效数字将被放置在最低有效位置buff.ie-12H在buff中存为21,因为buff中先存1,后存2。 little endian 和 big endian 在这里存储数字有什么重要性吗?如果是,请解释。
在 print 宏中,第二个参数始终是变量的大小 printed.Here,buff 的大小是 16 字节,因此第二个参数是 16。但是如果我将第二个参数设置为 8 那么为什么每个数组元素的一半数字没有被打印但仍然打印了整个 8 位数字。另外,请给我一个例子,其中将打印数组每个元素的一半数字,在这种情况下,将打印较高的 4 位有效数字还是打印较低的 4 位有效数字?还有,为什么?
- 零。
10
不是 msg
的大小。这些只是嵌入式换行符。大小计算为 len equ $-msg
,因此将始终与您提供的文本长度相匹配。
- 根据大小,符号位是最高有效位。因为你有 qwords,所以
11234H
是 0000000000011234H
并且是正数。 FFFFFFFFH
是一个很大的正数。 FFFFFFFFFFFFFFFFH
可能是更大的数字或 -1
,具体取决于您将其解释为无符号还是有符号。
- 没什么,就是
1
。它只是将 rsi
中的值加一。以后用作地址时,这将意味着 1 个字节。
- 那只是因为您的终端使用 ascii 代码,因此将打印
0
以获得 30h
的值(依此类推)。是的,如果您阅读文本,您将需要从 ascii 转换为二进制。
- 没错。
- 你描述的是对的,但不是反过来的。人类首先从最重要的数字开始。因此,代码将其放在首位并递增
rsi
以将其他数字放在它之后是有道理的。不确定为什么你认为这是相反的。
- 因为
print
是分别为每个数组元素调用的,因此缩短输出适用于每个元素而不是整个输出。当然,它会是更高的数字,因为这就是它们在内存中的方式。见上文第 7 点。
我是汇编编程的新手,正在尝试解释以下代码,我必须在其中打印 .data 部分中存在的数组: 这是代码:
%macro print 2
mov rax,1
mov rdi,1
mov rsi,%1
mov rdx,%2
syscall
%endmacro
%macro exit 0
mov rax,60
mov rdi,0
syscall
%endmacro
section .data
msg db 10,"Array is : ",10
len equ $-msg
array dq 11234H, 0AB32H, -3326H, 056BH
newline db 10
section .bss
buff resb 16;
section .code
global _start
_start:
print msg,len
mov rsi,array
mov rcx,4
back:
mov rbx,[rsi]
push rsi
push rcx
call HextoASCII
print newline,1
pop rcx
pop rsi
add rsi,8
loop back
exit
HextoASCII:
mov rsi,buff
mov rcx,16
back1:
rol rbx,4
mov al,bl
and al,0fh
cmp al,9h
jbe add_30h
add al,7h
add_30h:
add al,30h
mov [rsi],al
inc rsi
loop back1
print buff,16
ret
有几个问题想请教解惑:
.bss 部分中存在的变量的默认值是多少?
msg 的大小是 10 个字节(msg 的最大大小),但是当我在其中输入更多字符时,即使字符串大小超过其最大限制,它仍然会打印整个 msg( 10 个字节).
如果数组中给出的数字最后(最高有效位)为非零,是否意味着该数字为负数 ie.- 数组中的 11234H 不是负数,因为我假设最高有效位在内存中显示为 1 (FFF11234H)。我认为对于一个非负数,它的最高位必须是零(011234),这样高阶位在内存中存储为 0 并使数字为正数。 如果我在这里错了,那么要问的另一件事是 FFFFFFFFH 是 -1 还是一个大的正数。
我对指令感到困惑
inc rsi
据说rsi加1。但是这里的1是什么,bit还是byte还是8byte(rsi的大小)。
添加 30H 或 37H 会将十六进制数字转换为 39H 或 41H,这些是 9 和 A 在 ASCII 中的十六进制表示,但我不明白为什么打印 39H 或 41H 会产生结果 9 或 A在我的显示器上,而不是 39H 或 41H 本身。是不是无论我们的结果是什么,汇编程序都会在监视器上打印出它的 ASCII 等价物。此外,我们通过 assembler/machine 解释的键盘输入是以什么形式提供的?如果它是 ASCII,那么我是否需要将其显式转换回 HEX 以供以后计算?
添加 30H 或 37H 后,单位数字(0H-9H 或 AH-FH)将转换为双位数,范围为 30H-39H 和 41H - 46H,因此当我们将其移动到buff,转换后实际上不会占用数组元素的两倍大小到buff中存储吗?我假设之前数字占用 4 位,现在转换后占用 8 位(9h 是 4 位,39h 是 8 位)。如果我在这里错了,请纠正我。 如果我是对的,这就是为什么当每个数组元素大小仅为 8 字节(四字)时 buff 被视为 16 字节的原因吗?
我理解 HextoASCII 的逻辑,它获取数字的最高位并将其存储在 buff 中,然后继续打印 buff 但不会以相反的方式打印数字,因为数组元素的最高位存储在 buff 的最低有效位置,并且随着 rsi 递增,下一个数字将添加到 buff 的较高位置,因此如果我们打印 buff,那么最高有效数字将被放置在最低有效位置buff.ie-12H在buff中存为21,因为buff中先存1,后存2。 little endian 和 big endian 在这里存储数字有什么重要性吗?如果是,请解释。
在 print 宏中,第二个参数始终是变量的大小 printed.Here,buff 的大小是 16 字节,因此第二个参数是 16。但是如果我将第二个参数设置为 8 那么为什么每个数组元素的一半数字没有被打印但仍然打印了整个 8 位数字。另外,请给我一个例子,其中将打印数组每个元素的一半数字,在这种情况下,将打印较高的 4 位有效数字还是打印较低的 4 位有效数字?还有,为什么?
- 零。
10
不是msg
的大小。这些只是嵌入式换行符。大小计算为len equ $-msg
,因此将始终与您提供的文本长度相匹配。- 根据大小,符号位是最高有效位。因为你有 qwords,所以
11234H
是0000000000011234H
并且是正数。FFFFFFFFH
是一个很大的正数。FFFFFFFFFFFFFFFFH
可能是更大的数字或-1
,具体取决于您将其解释为无符号还是有符号。 - 没什么,就是
1
。它只是将rsi
中的值加一。以后用作地址时,这将意味着 1 个字节。 - 那只是因为您的终端使用 ascii 代码,因此将打印
0
以获得30h
的值(依此类推)。是的,如果您阅读文本,您将需要从 ascii 转换为二进制。 - 没错。
- 你描述的是对的,但不是反过来的。人类首先从最重要的数字开始。因此,代码将其放在首位并递增
rsi
以将其他数字放在它之后是有道理的。不确定为什么你认为这是相反的。 - 因为
print
是分别为每个数组元素调用的,因此缩短输出适用于每个元素而不是整个输出。当然,它会是更高的数字,因为这就是它们在内存中的方式。见上文第 7 点。