Распечатать список строк в сборке

Sep 18 2020

Как выглядит следующая программа для печати списка строк? Какие места я могу улучшить? Есть ли более простые способы напечатать что-то вроде разрыва строки после каждой строки, а не жестко закодировать \nсаму строку?

# Program, print out a list of strings, one per line
.data

SYS_EXIT   = 60
SYS_WRITE  = 1
SYS_STDOUT = 1

# Empty string means end of strings
strings:    .asciz  "Once\n", "upon\n", "a\n", "time\n", "...\n", ""

.text
.globl _start

get_string_length:
    mov $0, %eax .L1_loop: movzbl (%edi, %eax), %ecx cmp $0, %cl
    je .L1_exit
    inc %eax
    jmp .L1_loop
  .L1_exit:
    ret

_start:

    mov $strings, %rbx print_loop: mov %rbx, %rdi call get_string_length # (rdi=file_descriptor, rsi=starting_address, rdx=size) cmp $0, %eax
    jz exit
    mov $SYS_STDOUT,%edi mov %rbx, %rsi mov %eax, %edx mov $SYS_WRITE, %eax
    syscall
    lea 1(%eax, %ebx,), %ebx
    jmp print_loop

  exit:
    mov $0, %edi mov $SYS_EXIT, %eax
    syscall

Ответы

3 SepRoland Sep 26 2020 at 05:59

Есть ли более простые способы напечатать что-то вроде разрыва строки после каждой строки, а не жестко закодировать \ n в самой строке?

Встроенные символы новой строки, безусловно, являются самым простым способом сделать это, но определенно не самым универсальным способом. Встраивание символов новой строки как бы подталкивает вас к тому, что строки будут использоваться только для вывода. Возможно, вам захочется заняться с ними и другими вещами.
Я выступаю за то, чтобы строки оставались чистыми и позже добавляли разрывы строк или любой другой префикс или суффикс. Поскольку вам уже нужно подсчитать количество символов в строке, вы можете одновременно скопировать строку в буфер (каждая нетривиальная программа имеет наготове какой-то буфер общего назначения). После того, как вы прочитаете нулевой терминатор, вы сохраните новую строку в буфере. Затем вы готовы распечатать содержимое буфера, длина которого вам теперь известна.

В приведенном ниже коде PrepStringForOutput - это листовая функция, что означает, что вы можете делать в ней практически все, что захотите. Вам не обязательно соблюдать какие-либо правила регистрации как таковые.

# Program, print out a list of strings, one per line
.data

SYS_EXIT   = 60
SYS_WRITE  = 1
SYS_STDOUT = 1

# Empty string means end of strings
Strings:    .asciz  "Once", "upon", "a", "time", "...", ""
Buffer:     .ascii  "12345"

.text
.globl _start

; IN (%rbx is asciz) OUT (%rsi is buffer, %rdx is length) MOD (%al) 

PrepStringForOutput:
    mov     $Buffer, %rsi # Destination xor %edx, %edx # Length .L1_loop: mov (%rbx, %rdx), %al # Character from asciz string test %al, %al jz .L1_exit mov %al, (%rsi, %rdx) # Store in buffer inc %edx jmp .L1_loop .L1_exit: mov $10, (%rsi, %rdx)    # Adding newline
    inc     %edx
    ret

_start:

    mov     $Strings, %rbx PrintLoop: cmpb $0, (%rbx)           # End of list ?
    je      Exit
    call    PrepStringForOutput  # -> %rsi is address, %rdx is length
    add     %rdx, %rbx           # Advancing in the list
    mov     $SYS_STDOUT, %edi mov $SYS_WRITE, %eax
    syscall
    jmp     PrintLoop
  Exit:
    xor     %edi, %edi
    mov     $SYS_EXIT, %eax
    syscall

Какие места я могу улучшить?

Вы легко заметите их в приведенном выше коде ...
Видите красивую табличную структуру?