如何使用 write 系统调用打印整数?

问题描述

这是一个简单的项目,它从系统时钟创建一个随机数字。它需要一个数字,将其转换为一个数字,然后加上 48,以便在 ASCII 表中匹配。我的问题是它不打印任何东西。据我所知,它必须是一个字符串才能考虑打印。有没有办法可以“投射”它?就像是的,我知道,它是一个整数,但假装它在 ascii 表上?这是我的代码供参考。除了“prnt_clock”,一切正常。最后一件事,我不能使用任何 C 代码/函数,所以不,我不能使用 printf。

.global rand

.equ    STDOUT,1
.equ    WRITE,4

rand:
    PUSH    {LR}
    BL      get_clock
    LDR     R1,=time
    ADD     R1,R1,#5
    LDRB    R0,[R1]
    BL      num_to_digit
    ADD     R0,R0,#48
    MOV     R1,R0
    BL      prnt_clock
    B       rand_leave

get_clock:
    MOV     R7,#78         @ Get time of day
    LDR     R0,=time       @ address of holder for time_t
    MOV     R1,#0          @ time zone not needed
    SWI     0
    MOV     PC,LR

// Assumes the number is in R0
num_to_digit:
    CMP     R0,#9          @ Compare num to 9
    SUBGT   R0,#10     @ If greater than,substract 10
    BGT     num_to_digit    @ Repeat until its eq or lower than 9
    MOV     PC,LR          @ Comeback to main

prnt_clock:
    MOV     R0,#STDOUT     @ Print to terminal
    MOV     R2,#1          @ Print only the digit
    MOV     R7,#WRITE      @ Write Syscall
    @MOV        R3,#0          @ Create a counter
    SWI     0

rand_leave:
    POP     {LR}
    MOV     PC,LR

.data
time:   .space  9

解决方法

通常,您使用 printf 或其他库来打印整数。

如果您正在寻找独立程序,请使用编译器编译 C 以进行汇编输出:

/*
    r3 = magic division number
    r2 = division
    r0 = integer to be converted
*/

.syntax unified
.equ division,0x66666667 // 1717986919; (2 ^ 34 + 6) / 10

.section .text

    .global _start
    _start:
        push {ip}
        mov r1,#0x0a // 10; newline
        push {r1}
        mov r7,#0x04 // write syscall
        /*
            If your architecture is ARMv7 (or above).
            movw r3,#:lower16:division // 26215
            movt r3,#:upper16:division // 26214
        */
        ldr r3,=division
        mov r0,#(0x01 << 0x1e) // replace this

    _division:
        smmul r1,r0,r3
        asr r2,r1,#0x02

    _modulo:
        add r1,r2,lsr #0x1f // 31
        add r1,lsl #0x02
        sub r0,lsl #0x01

    _string:
        add r0,#0x30 // 48; '0'
        push {r0}

    _shift:
        mov r0,r2
        cmp r0,#0x00
        bne _division

    _write:
        mov r1,sp
        ldr r3,[r1]
        cmp r3,#0x00
        beq _end

        mov r0,#0x01 // stdout file descriptor
        pop {ip}
        mov r2,#0x01 // length
        swi 0x00 // execute syscall

        bne _write


    _end:
        pop {ip}
        mov r7,#0x01 // exit syscall
        mov r0,#0x00 // exit status
        swi 0x00 // execute syscall

Github(更新更多):https://raw.githubusercontent.com/GrpeApple/Assembly/test/ARM/src/arm/int2str.S

如果您希望这是您的依赖项:https://raw.githubusercontent.com/GrpeApple/Assembly/test/ARM/src/deps/int2str.S(使用寄存器 r0-r2

请参阅 Why does GCC use multiplication by a strange number in implementing integer division? 以了解比实际除法指令更有效地除以 10 的 smmul / asr 技巧。

您使用模和除法分别获得最后一个整数和倒数第二个整数。您使用除法检查直到为零。

它添加了 '0' 的 ascii 值。 我也包含在 ARMv7 的评论中。