1

Welcome.

I have following code:

%define ESC 0x1b

section .text
global _start
_start:
.drawer:
    call getdata
    mov rdi, 1
    call sleep
    jmp .drawer
    mov rdi, 0
    mov rax, 60                 ;; sys_exit
    syscall                     ;; exit

sleep:
    mov [timespec.tv_sec], rdi
    xor rdi, rdi
    mov [timespec.tv_usec], rdi
    mov rdi, timespec
    xor rsi, rsi
    mov rax, 35                 ;; sys_nanosleep
    syscall                     ;; nanosleep
    ret

getuptime:
    mov rdx, 16
    mov rsi, data.uptimebuf
    mov rdi, filename.uptime
    call readfile
    mov rdi, rsi
    mov rsi, 0x2e               ;; ASCII '.'
    call strclen
    mov rsi, rax
    call stoin
    mov qword [data.uptime], rax
    mov rdi, qword [data.uptime]
    call printi
    ret

getdata:
    call getuptime
    ret

section .data
data:
    .uptime dq 0
    .uptimebuf times 16 db 0
timespec:
    .tv_sec dq 0
    .tv_usec dq 0

section .rodata
ansi:
    .clear db ESC, "[2J", ESC, "[H"
    .clearlen equ $ - .clear
filename:
    .uptime db "/proc/uptime"

;; Content under this line is included on beginning like this:
;; %include "libasm.asm"
;; under line
;; %define ESC 0x1b

section .text

strlen: ;; string: rdi
    push rbx
    mov rbx, rdi
.again:
    cmp byte [rbx], 0
    jz .done
    inc rbx
    jmp .again
.done:
    sub rbx, rdi
    mov rax, rbx
    pop rbx
    ret

strclen: ;; string: rdi, char: rsi
    push rbx
    mov rbx, rsi
    mov al, bl
    mov rbx, rdi
.again:
    cmp byte [rbx], 0
    jz .done
    cmp byte [rbx], al
    je .done
    inc rbx
    jmp .again
.done:
    sub rbx, rdi
    mov rax, rbx
    pop rbx
    ret

printn: ;; string: rdi, len: rsi
    push rdx
    push rsi
    push rdi
    mov rdx, rsi
    mov rsi, rdi
    mov rdi, 1
    mov rax, 1                  ;; sys_write
    syscall                     ;; write(unsigned int fd, const char *buf, size_t count)
    pop rdi
    pop rsi
    pop rdx
    ret

stoin: ;; string: rdi, len: rsi
    push rdx
    push rcx
    push rbx
    mov rdx, rdi
    xor rcx, rcx
    xor rax, rax
.again:
    mov rbx, 10
    cmp rcx, rsi
    jge .done
    push rdx
    mul rbx
    pop rdx
    xor rbx, rbx
    mov bl, byte [rdx]
    sub bl, 0x30                    ;; ASCII '0'
    add rax, rbx
    inc rdx
    inc rcx
    jmp .again
.done:
    pop rbx
    pop rcx
    pop rdx
    ret

readfile: ;; filename: rdi, buffer: rsi, length: rdx
    push rsi
    xor rsi, rsi
    mov rax, 2                  ;; sys_open
    syscall                     ;; open(char *filename, int flags, int mode)
    pop rsi
    push rdi
    mov rdi, rax
    mov rax, 0                  ;; sys_read
    syscall                     ;; read(unsigned int fd, const char *buf, size_t count)
    mov rax, 3                  ;; sys_close
    syscall                     ;; close(unsigned int fd);
    pop rdi
    ret

printi: ;; long: rdi
    extern printf
    section .data
    fmt db "%ld", 10, 0
    section .text
    push rsi
    mov rsi, rdi
    mov rdi, fmt
    call printf
    pop rsi
    ret

If it stays like that, everyething works properly, but I want to move last 2 instructions before ret in getuptime function to place just after calling getuptime, just like that:

getuptime:
    mov rdx, 16
    mov rsi, data.uptimebuf
    mov rdi, filename.uptime
    call readfile
    mov rdi, rsi
    mov rsi, 0x2e               ;; ASCII '.'
    call strclen
    mov rsi, rax
    call stoin
    mov qword [data.uptime], rax
    ret

getdata:
    call getuptime
    mov rdi, qword [data.uptime]
    call printi
    ret

but when I'll do it, i am getting Segmentation Fault or Bus Error. Why?

kocotian
  • 97
  • 1
  • 7
  • Where is `stoin` defined? – fuz Apr 21 '21 at 17:23
  • Edited with pastebin link containing all functions – kocotian Apr 21 '21 at 17:28
  • Stack Overflow questions must be self-contained. I won't even look at external links. Please edit the code into the question, or even better, provide a [mcve] that is as short as possible and can be assembled and run without any external dependencies. – fuz Apr 21 '21 at 17:39
  • I notice it doesn’t maintain stack alignment. It’s possible that printi requires a properly aligned stack, which is why it fails when called from a different function. The stack should be aligned to a multiple of 16 before the call. Stack alignment is typically maintained by subtracting 8 (or an odd multiple of 8) at the start of each function. – prl Apr 21 '21 at 17:56
  • 1
    @fuz, edited with minimal reproducible example – kocotian Apr 21 '21 at 18:03
  • @prl printi uses printf from (musl) libc, so probably that's the main problem - when I removed printi, i don't get segfault. But my question - how, or maybe where, could I align stack in assembly? In addition, usage of libc is temporary for "debugging", so I don't want to add too much code that i will delete. – kocotian Apr 21 '21 at 18:05
  • 1
    @kocotian Thanks for the edits. prl is probably right in that it could be a stack alignment issue. – fuz Apr 21 '21 at 18:07
  • 1
    You should also `xor eax,eax` before printf to zero AL, because you're passing 0 FP args in XMM registers. But see also [glibc scanf Segmentation faults when called from a function that doesn't align RSP](https://stackoverflow.com/q/51070716) - even that might not be enough to avoid segfaults with a misaligned RSP. – Peter Cordes Apr 21 '21 at 20:05
  • 1
    In _start, the stack is aligned. In other function that doesn’t use the stack, subtract 8 from rsp at the beginning and add 8 at the end. In any function that pushes registers, either push an odd number of registers or subtract an additional 8 bytes. – prl Apr 22 '21 at 00:28
  • Alternatively, in printi, do `push rsi; push r15; mov r15, rsp; and rsp, -16; ... ; mov rsp, r15; pop r15; pop rsi; ret` – prl Apr 22 '21 at 00:31
  • @prl: if you're going to `and rsp, -16`, it's normal to use RBP to save the old RSP like when using it as a frame pointer. (You can access aligned locals relative to RSP) – Peter Cordes Apr 22 '21 at 03:14
  • 1
    @Peter, I just did that out of habit because I prefer to use rbp for a 32-bit register or an address register. Nanooptimizations, you know. :-) Of course by that rule I should have used r12 or r13. – prl Apr 22 '21 at 06:03
  • @prl: Ah, that's fair if you're not going to address any stack-args or less-aligned locals relative to RBP, and not going to use `leave` for code-size. So yeah good point about using up R12 or R13 for that, the worst registers for pointers. – Peter Cordes Apr 22 '21 at 06:28

0 Answers0