Как мне записать значение в RAX в STDOUT в сборке? - PullRequest
3 голосов
/ 24 августа 2011

Я могу использовать syscall для записи, чтобы напечатать некоторые данные в памяти в STDOUT:

ssize_t write(int fd, const void *buf, size_t count);

То есть:

movq    $1, %rax
movq    $1, %rdi
move address_of_variable %rsi
movq    $5, %rdx
syscall

Но как я могу напечатать значения регистров?

UPDATE

.text
        call start
    start:
        movq $100, %rdi
        movq $10, %rsi
        call print_number
        ret

    buffer:
        .skip 64
    bufferend:
    # rdi = number
    # rsi = base
    print_number:
        leaq bufferend, %rcx
        movq %rdi, %rax
    1:
        xorq %rdx, %rdx
        divq %rsi

        add $'0', %dl
        cmp $'9', %dl
        jbe 2f
        add $'A'-'0'-10, %dl

    2:
        sub $1, %rcx
        mov %dl, (%rcx)

        and %rax, %rax
        jnz 1b

        mov %rcx, %rsi
        lea bufferend, %rdx
        sub %rcx, %rdx

        movq    $1, %rax
        movq    $1, %rdi
        syscall
        ret

Ответы [ 2 ]

3 голосов
/ 24 августа 2011

Вы должны сначала преобразовать его в текст. Вы можете пойти по простому маршруту и ​​использовать, например, printf из libc или, если вы хотите, напишите свою собственную утилиту преобразования.

Обновление: если вы хотите, чтобы код был позиционно независимым, проще использовать стек. Простое перемещение буфера в сегмент кода, поскольку код, на который вы ссылаетесь в комментариях, больше не работает, поскольку современные процессоры имеют сегменты кода только для чтения. Я обновил код для использования стека для временного хранения.

    .text

    call start
start:
    movq    $186, %rax # sys_gettid
    syscall

    movq %rax, %rdi
    movq $10, %rsi
    call print_number

    #ret
    mov $60, %rax # sys_exit
    mov $0, %rdi
    syscall

# rdi = number
# rsi = base
print_number:
    sub $72, %rsp # alloc room for buffer on the stack, 8 more than needed

    lea 64(%rsp), %rcx # 64(%rsp) == buffer end
    movq %rdi, %rax # rax holds current number 
1:
    xorq %rdx, %rdx # clear rdx (div uses the 128-bit number in rdx:rax)
    divq %rsi # divide by base, updating rax for the next iteration 
              # and giving us our digit in rdx (dl)
    add $'0', %dl # turn into printable character
    cmp $'9', %dl # handle digits > 10
    jbe 2f
    add $'A'-'0'-10, %dl # adjust number so A=10, B=11 ...

2:
    sub $1, %rcx # subtract before adding character as we start from the end
    mov %dl, (%rcx) # store character in string

    and %rax, %rax # rax == 0?
    jnz 1b # if not, then keep working

    mov %rcx, %rsi # buf = address of last character stored
    lea 64(%rsp), %rdx # calculate length by subtracting buffer end
    sub %rcx, %rdx # from the buffer start

    movq $1, %rax # sys_write
    movq $1, %rdi # fd = STDOUT_FILENO
    syscall

    add $72, %rsp # adjust stack back
    ret

Если, наоборот, вы хотите сохранить буфер в сегменте кода, это может быть сделано. Вы должны отметить страницу, где buffer находится как доступная для записи, например, используя mprotect(2). Здесь сделано без проверки ошибок (и при условии sysconf(_SC_PAGE_SIZE) == 4096) в сборке:

     mov $10, %rax # sys_mprotect
     lea buffer, %rdi # addr
     and $-4096, %rdi # page align
     mov $4096, %rsi # len
     mov $7, %rdx #prot = PROT_READ|PROT_WRITE|PROT_EXEC
     syscall

И теперь код должен работать, даже если буфер находится в сегменте кода. Кстати, я использую sys_exit в своем примере, потому что я тестирую его как отдельный файл с gcc x.s -nostdlib -ggdb -o x.

Update2: чтобы использовать его при перемещении кода, используйте RIP-относительную адресацию. Измените bufferend на bufferend(%rip).

0 голосов
/ 24 августа 2011

вы не можете писать чистые числа (так как они будут интерпретироваться как указатели), вам нужно преобразовать это число в строку и передать указатель на эту строку как аргумент write.что-то вроде этого .

...