如何在 Mac 上的 x86 程序集 (NASM) 中打印有符号整数
How to print signed integer in x86 assembly (NASM) on Mac
我在 x86 汇编中发现了一个 implementation 的无符号整数转换,我尝试将其插入,但作为汇编的新手并且还没有调试环境,很难理解为什么它不起作用。我还希望它能处理有符号整数,这样它就可以从系统调用中捕获错误消息。
想知道是否可以说明如何修复此代码以打印带符号整数,而不使用 printf,而是使用 this 答案提供的 strprn
。
%define a rdi
%define b rsi
%define c rdx
%define d r10
%define e r8
%define f r9
%define i rax
%define EXIT 0x2000001
%define EXIT_STATUS 0
%define READ 0x2000003 ; read
%define WRITE 0x2000004 ; write
%define OPEN 0x2000005 ; open(path, oflag)
%define CLOSE 0x2000006 ; CLOSE
%define MMAP 0x2000197 ; mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset)
; szstr computes the lenght of a string.
; rdi - string address
; rdx - contains string length (returned)
strsz:
xor rcx, rcx ; zero rcx
not rcx ; set rcx = -1 (uses bitwise id: ~x = -x-1)
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec rcx through NUL)
not rcx ; rev all bits of negative -> absolute value
dec rcx ; -1 to skip the null-term, rcx contains length
mov rdx, rcx ; size returned in rdx, ready to call write
ret
; strprn writes a string to the file descriptor.
; rdi - string address
; rdx - contains string length
strprn:
push rdi ; push string address onto stack
call strsz ; call strsz to get length
pop rsi ; pop string to rsi (source index)
mov rax, WRITE ; put write/stdout number in rax (both 1)
mov rdi, 1 ; set destination index to rax (stdout)
syscall ; call kernel
ret
; mov ebx, 0xCCCCCCCD
itoa:
xor rdi, rdi
call itoal
ret
; itoa loop
itoal:
mov ecx, eax ; save original number
mul ebx ; divide by 10 using agner fog's 'magic number'
shr edx, 3 ;
mov eax, edx ; store quotient for next loop
lea edx, [edx*4 + edx] ; multiply by 10
shl rdi, 8 ; make room for byte
lea edx, [edx*2 - '0'] ; finish *10 and convert to ascii
sub ecx, edx ; subtract from original number to get remainder
lea rdi, [rdi + rcx] ; store next byte
test eax, eax
jnz itoal
exit:
mov a, EXIT_STATUS ; exit status
mov i, EXIT ; exit
syscall
_main:
mov rdi, msg
call strprn
mov ebx, -0xCCCCCCCD
call itoa
call strprn
jmp exit
section .text
msg: db 0xa, " Hello Whosebug!!!", 0xa, 0xa, 0
通过这项工作,可以将有符号整数正确打印到 STDOUT,因此您可以记录寄存器值。
- https://codereview.stackexchange.com/questions/142842/integer-to-ascii-algorithm-x86-assembly
- How to print a string to the terminal in x86-64 assembly (NASM) without syscall?
- How do I print an integer in Assembly Level Programming without printf from the c library?
- https://baptiste-wicht.com/posts/2011/11/print-strings-integers-intel-assembly.html
我在您已经链接的 How do I print an integer in Assembly Level Programming without printf from the c library? 上的回答表明,将一个整数序列化为 ASCII 十进制的内存会为您提供一个长度,因此您在这里没有用 strlen
的(自定义版本) .
(你的 msg
有一个 assemble 时间常数长度,所以不使用它是愚蠢的。)
要打印有符号整数,请执行以下逻辑:
if (x < 0) {
print('-'); // or just was_negative = 1
x = -x;
}
unsigned_intprint(x);
Unsigned 涵盖 abs(most_negative_integer)
案例,例如在 8 位中 - (-128)
溢出到 -128
有符号。但是,如果您将条件 neg
的结果视为 unsigned,那么它是正确的,所有输入都没有溢出。
与其实际打印 -
本身,只需保存起始数字为负数的事实 并将 -
粘贴在 -
前面生成最后一个数字后的其他数字。对于不是 2 的幂的基数,普通算法只能以相反的打印顺序生成数字,
我的带有系统调用答案的 x86-64 打印整数将输入视为无符号,因此您应该简单地将其与一些符号处理代码一起使用。它是为 Linux 编写的,但替换 write
系统调用号将使它在 Mac 上运行。它们具有相同的调用约定和 ABI。
顺便说一句,xor al,al
严格来说比 xor eax,eax
差,除非你特别 想要 保留 RAX 的高 7 字节。只有完整寄存器的异或归零是 .
此外,repnz scasb
不快;对于大字符串,每个时钟大约进行 1 次比较。
对于最多 16 个字节的字符串,您可以使用带有 pcmpeqb
/ pmovmskb
/ bsf
的单个 XMM 向量来查找第一个零字节,无需循环。 (SSE2 是 x86-64 的基准)。
我在 x86 汇编中发现了一个 implementation 的无符号整数转换,我尝试将其插入,但作为汇编的新手并且还没有调试环境,很难理解为什么它不起作用。我还希望它能处理有符号整数,这样它就可以从系统调用中捕获错误消息。
想知道是否可以说明如何修复此代码以打印带符号整数,而不使用 printf,而是使用 this 答案提供的 strprn
。
%define a rdi
%define b rsi
%define c rdx
%define d r10
%define e r8
%define f r9
%define i rax
%define EXIT 0x2000001
%define EXIT_STATUS 0
%define READ 0x2000003 ; read
%define WRITE 0x2000004 ; write
%define OPEN 0x2000005 ; open(path, oflag)
%define CLOSE 0x2000006 ; CLOSE
%define MMAP 0x2000197 ; mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t offset)
; szstr computes the lenght of a string.
; rdi - string address
; rdx - contains string length (returned)
strsz:
xor rcx, rcx ; zero rcx
not rcx ; set rcx = -1 (uses bitwise id: ~x = -x-1)
xor al,al ; zero the al register (initialize to NUL)
cld ; clear the direction flag
repnz scasb ; get the string length (dec rcx through NUL)
not rcx ; rev all bits of negative -> absolute value
dec rcx ; -1 to skip the null-term, rcx contains length
mov rdx, rcx ; size returned in rdx, ready to call write
ret
; strprn writes a string to the file descriptor.
; rdi - string address
; rdx - contains string length
strprn:
push rdi ; push string address onto stack
call strsz ; call strsz to get length
pop rsi ; pop string to rsi (source index)
mov rax, WRITE ; put write/stdout number in rax (both 1)
mov rdi, 1 ; set destination index to rax (stdout)
syscall ; call kernel
ret
; mov ebx, 0xCCCCCCCD
itoa:
xor rdi, rdi
call itoal
ret
; itoa loop
itoal:
mov ecx, eax ; save original number
mul ebx ; divide by 10 using agner fog's 'magic number'
shr edx, 3 ;
mov eax, edx ; store quotient for next loop
lea edx, [edx*4 + edx] ; multiply by 10
shl rdi, 8 ; make room for byte
lea edx, [edx*2 - '0'] ; finish *10 and convert to ascii
sub ecx, edx ; subtract from original number to get remainder
lea rdi, [rdi + rcx] ; store next byte
test eax, eax
jnz itoal
exit:
mov a, EXIT_STATUS ; exit status
mov i, EXIT ; exit
syscall
_main:
mov rdi, msg
call strprn
mov ebx, -0xCCCCCCCD
call itoa
call strprn
jmp exit
section .text
msg: db 0xa, " Hello Whosebug!!!", 0xa, 0xa, 0
通过这项工作,可以将有符号整数正确打印到 STDOUT,因此您可以记录寄存器值。
- https://codereview.stackexchange.com/questions/142842/integer-to-ascii-algorithm-x86-assembly
- How to print a string to the terminal in x86-64 assembly (NASM) without syscall?
- How do I print an integer in Assembly Level Programming without printf from the c library?
- https://baptiste-wicht.com/posts/2011/11/print-strings-integers-intel-assembly.html
我在您已经链接的 How do I print an integer in Assembly Level Programming without printf from the c library? 上的回答表明,将一个整数序列化为 ASCII 十进制的内存会为您提供一个长度,因此您在这里没有用 strlen
的(自定义版本) .
(你的 msg
有一个 assemble 时间常数长度,所以不使用它是愚蠢的。)
要打印有符号整数,请执行以下逻辑:
if (x < 0) {
print('-'); // or just was_negative = 1
x = -x;
}
unsigned_intprint(x);
Unsigned 涵盖 abs(most_negative_integer)
案例,例如在 8 位中 - (-128)
溢出到 -128
有符号。但是,如果您将条件 neg
的结果视为 unsigned,那么它是正确的,所有输入都没有溢出。
与其实际打印 -
本身,只需保存起始数字为负数的事实 并将 -
粘贴在 -
前面生成最后一个数字后的其他数字。对于不是 2 的幂的基数,普通算法只能以相反的打印顺序生成数字,
我的带有系统调用答案的 x86-64 打印整数将输入视为无符号,因此您应该简单地将其与一些符号处理代码一起使用。它是为 Linux 编写的,但替换 write
系统调用号将使它在 Mac 上运行。它们具有相同的调用约定和 ABI。
顺便说一句,xor al,al
严格来说比 xor eax,eax
差,除非你特别 想要 保留 RAX 的高 7 字节。只有完整寄存器的异或归零是
此外,repnz scasb
不快;对于大字符串,每个时钟大约进行 1 次比较。
对于最多 16 个字节的字符串,您可以使用带有 pcmpeqb
/ pmovmskb
/ bsf
的单个 XMM 向量来查找第一个零字节,无需循环。 (SSE2 是 x86-64 的基准)。