【问题标题】:How do I print an integer with the write syscall?如何使用 write 系统调用打印整数?
【发布时间】:2021-03-16 20:18:50
【问题描述】:

这是一个从系统时钟创建随机数字的简单项目。它需要一个数字,将其转换为数字,然后添加 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, 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

【问题讨论】:

  • 您需要将整数(ascii char)存储在内存中并传递其地址。见 man 2 写。
  • 那么我如何将它存储在内存中呢?我是否制作一个充满空格的标签 asciz 然后将其存储在里面?老实说,我不知道我该怎么做。我试过STR和LDR。但我找不到将整数存储在内存中的方法/
  • 是的,分配一个静态缓冲区会起作用。它不必以零结尾,如果它是单个数字(字符),您可以使用STRB。您也可以将其推送到堆栈并传递其地址(但之后不要忘记清理它)。
  • 重复减法对于 div/remainder 来说是一种非常慢的算法,尤其是对于像 10 这样的小除数。请参阅 How do I print an integer in Assembly Level Programming without printf from the c library? 了解 C 算法和 x86 Linux asm 实现。您可以编译 C 以获得 ARM 代码,并将堆栈空间缓冲区处理从我的 x86 asm 调整到 ARM。

标签: assembly raspberry-pi arm raspbian


【解决方案1】:

通常,您使用 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, r1, lsr #0x1f // 31
        add r1, r1, r1, lsl #0x02
        sub r0, r0, r1, 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? 了解 smmul / asr 技巧,它比实际除法指令更有效地除以 10。

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

它添加 '0' 的 ascii 值。 我还包含在 ARMv7 的 cmets 中。

【讨论】:

  • 如果您有代码要分享,特别是如果您只是为这个答案编写代码,直接将其包含在您的答案中(在带有三个反引号的代码块中),而不是通过一条链接。 (尤其是非站外链接;如果问题本身不应该作为重复而关闭,则可以链接其他 SO Q&A。)
  • 是的,我的想法是:“我正在不断更新 github repo,所以我可能会链接它。”但我没有意识到我可以同时包含两者。
  • 哦,是的,您仍然可以包含一个链接,并说明它可能比答案更新,只要您在此处包含代码。
  • 如果您使用不同的寄存器,ldr r1, =division 可能会被提升出循环,特别是如果您在缓冲区中生成一个字符串并为整个调用 write once东西,比如How do I print an integer in Assembly Level Programming without printf from the c library? 中的 C。然后你不需要将系统调用 args 放在 regs 中,直到最后一次。
猜你喜欢
  • 2011-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多