Assembly 将存储在EDX:EAX中的64位数字打印到标准输出
我在EDX:EAX中存储了大的64位数字,分别为21C3677C:82B40000。我正试图将数字以十进制2432902008176640000打印到控制台。是否有系统调用允许我完成此操作?哪个操作系统?在linux上,您使用Assembly 将存储在EDX:EAX中的64位数字打印到标准输出,assembly,x86,system-calls,32-bit,Assembly,X86,System Calls,32 Bit,我在EDX:EAX中存储了大的64位数字,分别为21C3677C:82B40000。我正试图将数字以十进制2432902008176640000打印到控制台。是否有系统调用允许我完成此操作?哪个操作系统?在linux上,您使用write系统调用。这是通过您正在使用的语言的标准库来完成的。您必须自己完成从二进制ASCII字符到十进制ASCII字符的转换,然后将write系统调用指向该ASCII文本,给出其长度,并告诉它要写入哪个文件描述符,stdout将是文件描述符1 这里有一种方法可以找出Lin
write
系统调用。这是通过您正在使用的语言的标准库来完成的。您必须自己完成从二进制ASCII字符到十进制ASCII字符的转换,然后将write
系统调用指向该ASCII文本,给出其长度,并告诉它要写入哪个文件描述符,stdout将是文件描述符1
这里有一种方法可以找出Linux中使用了什么系统调用。编写一个简单的程序并在strace
下调用它,该程序将跟踪程序进行的所有系统调用
例如,我写了这个C++程序< /p>
#include <iostream>
int main( int argc, char* argv[] )
{
static volatile unsigned long long x = 0x21C3677C82B40000;
std::cout << x << std::endl;
return 0;
}
然后使用strace
将stderr重定向到文件main.trace
$ strace -y ./main 2> main.trace
2432902008176640000
$
它写的是你期望的十进制数。通过在跟踪中搜索“dev”来查找设备的I/O
$ grep dev main.trace
fstat(1</dev/pts/3>, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
write(1</dev/pts/3>, "2432902008176640000\n", 20) = 20
$
$grep dev main.trace
fstat(1,{st_mode=S_IFCHR | 0620,st_rdev=makedev(136,3),…})=0
写入(1,“2432902008176640000\n”,20)=20
$
<>你会注意到C++标准库对<代码> STDUD> <代码>(1)的文件描述符做了<代码> fSTAT <代码>,随后是“代码>写/代码>系统调用,指针指向数据<代码> 243290200817664000 \n/COD>长度>代码> 20 < < /P> > P有人必须怜悯这家伙和他的同学。如果“justcallprintf”不是作弊,那么使用它也不应该是作弊。我从我遇到的第一个asm程序中偷了这个。它使用DOS中断查找磁盘大小,并每隔三位数打印一次带有逗号的
dx:ax
。你们可能不需要逗号。我已经对它进行了多年的修补——可能很快就会有一个rdx:rax
版本。非常适合显示阶乘。这是非常幼稚和低效的,但仍然有效。请随意改进它。当然,在缓冲区中有了角色之后,就只有“Hello World”和不同的歌词了
;-----------------------------------------------
; u64toda - converts (64 bit) integer in edx:eax
; to (comma delimited) decimal representation in
; zero (was "$") terminated string in buffer pointed to by edi
;----------------------------------------
u64toda:
pusha
mov ebx, edx ; stash high dword
mov esi,0Ah ; prepare to divide by 10
xor ecx, ecx ; zero the digit count
jmp highleft ; check is high word 0 ?
highword:
xchg eax,ebx ; swap high & low words
xor edx,edx ; zero edx for the divide!
div esi ; divide high word by 10
xchg eax,ebx ; swap 'em back
div esi ; divide low word including remainder
push edx ; remainder is our digit - save it
inc ecx ; count digits
highleft:
or ebx,ebx
jnz highword
lowleft:
xor edx,edx ; zero high word
div esi ; divide low word by 10
push edx ; our digit
inc ecx ; count it
or eax,eax ; 0 yet ?
jne lowleft
cmp ecx, byte 4 ; commas needed ?
jl write2buf ; nope
xor edx,edx ; zero high word for divide
mov eax,ecx ; number of digits
mov ebx,3
div ebx
mov esi,edx ; remainder = number digits before comma
test edx,edx
jnz write2buf ; no remainder?
mov esi,3 ; we can write 3 digits, then.
write2buf:
pop eax ; get digit back - in right order
add al,30H ; convert to ascii character
stosb ; write it to our buffer
dec esi ; digits before comma needed
jnz moredigits ; no comma needed yet
cmp ecx,2 ; we at the end?
jl moredigits ; don't need comma
mov al,',' ; write a comma
stosb
mov esi,03h ; we're good for another 3 digits
moredigits:
loop write2buf ; write more digits - cx of 'em
mov al,00h ; terminate buffer with zero
stosb
popa
ret
;------------------------
;-----------------------------------------------
; u64toda-转换edx:eax中的(64位)整数
; 到中的(逗号分隔的)十进制表示形式
; edi指向的缓冲区中以“$”结尾的字符串为零
;----------------------------------------
u64toda:
普沙
mov ebx、edx;藏高德沃德
movesi,0Ah;准备除以10
异或ecx,ecx;将数字计数归零
jmp左上角;检查是否为高位字0?
高地:
xchg-eax,ebx;交换高低字
xor-edx,edx;零edx表示除法!
分区esi;将高单词除以10
xchg-eax,ebx;换回来
分区esi;除低位字,包括余数
推动edx;余数是我们的数字-保存它
ecx公司;数数数字
左上方:
还是ebx,ebx
jnz高字
低空:
xor-edx,edx;零高位字
分区esi;将低位字除以10
推动edx;我们的数字
ecx公司;数一数
或eax,eax;0了吗?
低空
cmp-ecx,字节4;需要逗号吗?
jl write2buf;不
xor-edx,edx;零高位字表示除法
mov-eax,ecx;位数
mov-ebx,3
div ebx
mov esi,edx;余数=逗号前的数字
测试edx,edx
jnz write2buf;没有余数?
movesi,3;那么我们可以写3位数字。
write2buf:
pop-eax;以正确的顺序返回数字
添加铝,30小时;转换为ascii字符
stosb;将其写入缓冲区
dec esi;需要逗号前的数字
jnz-moredigits;还不需要逗号
cmp-ecx,2;我们到底在干什么?
jl-更多数字;不需要逗号
mov al,',';写一个逗号
斯托斯
movesi,03h;我们还有3位数
更多数字:
循环写入2buf;写更多的数字-它们的cx
mov-al,00h;用零终止缓冲区
斯托斯
波帕
ret
;------------------------
下面是一个如何使用printf打印64位数字的示例。这段代码与YASM一起工作
segment .data
format db "Number %ld", 0x0a, 0 ; Format string for printf
result dq 0 ; Quad word to store the EDX:EAX result in
segment .text
global main
extern printf
main:
; Store the 64 bit number in the quad word "result"
mov edx, 0x21C3677C ; Store the EDX value
mov eax, 0x82B40000 ; Store the EAX value
mov [result], eax ; Lower half of "result" will be EAX
mov [result+4], edx ; Upper half of "result" will be EDX
; Print "result" with the printf function
xor eax, eax ; No float parameters for printf
lea rdi, [format] ; First parameter for printf (format string)
mov rsi, [result] ; Second parameter for printf ("result")
call printf ; Call printf
; End program
xor eax, eax ; Return 0
ret
使用以下命令生成二进制文件:
yasm -f elf64 example.asm
gcc -o example example.o
更新:不使用内存的示例
segment .data
format db "Number %ld", 0x0a, 0 ; Format string for printf
segment .text
global main
extern printf
main:
; Store the 64 bit number in register rsi
mov edx, 0x21C3677C ; Store the EDX value (upper half)
mov eax, 0x82B40000 ; Store the EAX value (lower half)
mov esi, edx ; Place upper half in esi
shl rsi, 32 ; Shift left 32 bits
or rsi, rax ; Place the lower half in rsi
; Print "result" with the printf function
xor eax, eax ; No float parameters for printf
lea rdi, [format] ; First parameter for printf (format string)
call printf ; Call printf
; End program
xor eax, eax ; Return 0
ret
为什么要通过内存获取
edx:eax
到rsi
?shift/or或shift/shld将完成此操作。更有趣的是使用32位代码的示例。(这应该仍然有效:我认为32位系统上的printf应该仍然支持int64_t
)。当然可以使用rsi
或其他寄存器,但我认为这样的代码更具可读性。我用一个额外的例子更新了答案,没有使用内存空间。你真的不需要一个div
3。只需使用向下计数器并在其变为零时插入逗号(并将计数器重置为3)<代码>如果(!--counter){counter=3;插入逗号;}。i、 e.dec ebp/jz.逗号和重置
。
segment .data
format db "Number %ld", 0x0a, 0 ; Format string for printf
segment .text
global main
extern printf
main:
; Store the 64 bit number in register rsi
mov edx, 0x21C3677C ; Store the EDX value (upper half)
mov eax, 0x82B40000 ; Store the EAX value (lower half)
mov esi, edx ; Place upper half in esi
shl rsi, 32 ; Shift left 32 bits
or rsi, rax ; Place the lower half in rsi
; Print "result" with the printf function
xor eax, eax ; No float parameters for printf
lea rdi, [format] ; First parameter for printf (format string)
call printf ; Call printf
; End program
xor eax, eax ; Return 0
ret