Problems with "snd_pcm_hw_params_set_rate_near" and "snd_pcm_hw_params_set_period_size_near" in x86_64 assembly.

alsa-project/alsa-lib issue #471 was opened from sc1ntilla:
### **PREAMBLE:**
I have never worked with any sound system before, so I'm almost sure that it's just me doing something wrong, but I can't see what, so I'm asking for help.
I'm doing this project for fun, and to learn a lot of stuff, so feel free to give your opinions / advice if you want to.
### **WHAT HAPPENS:**
When calling `snd_pcm_hw_params_set_rate_near` and `snd_pcm_hw_params_set_period_size_near` memory protection violation is issued. I find that strange, because `snd_pcm_hw_params_set_buffer_size_near` works perfectly fine, and it's similiar to these two.
### **WHAT I TRIED:** - Making sure that stack after call is on address divisible by 96 (by adding 8 to stack pointer), - Making sure that `*val` argument is on address divisible by 96, - Misaligning stack by 8, 16, 24 and 32 before calling these functions (by subtracting from stack pointer), - Providing 0 to `*val` argument, to rule out that writing to output crashes, - Providing valid output address to `*dir` argument to rule out that 0 is causing crashes, - Calling these functions in different order, - Trying to call `snd_pcm_set_params` instead, but it says _"Channels count (0) not available for PLAYBACK: Invalid argument"_ however, I'm sure that I provided a valid number (2). I even hardcoded it.
But to no avail. Is it my misunderstanding of how alsa-lib works? Very likely. Is my assembly code faulty? Quite possible. I just can't see where the problem lies. If you see error somewhere, please let me know.
### **ADDITIONAL INFORMATION:**
I have multiple audio outputs: monitors with built-in speakers, standalone speakers, and analog jack headphones. I hardcoded `hw:2,0` as device name to open. Sometimes it results in `snd_pcm_open` returning _"File descriptor in bad state"_. When I tried using `sysdefault` it often returns _"ALSA lib /var/tmp/portage/media-libs/alsa-lib-1.2.14/work/alsa-lib-1.2.14/src/pcm/pcm_dmix.c:1000:(snd_pcm_dmix_open) unable to open slave"_
Below is .data section in which globals are stored, and source of function that will be used to play audio buffers.
.data section:
``` .section .data .align 32
test2: .8byte 0 test: .8byte 0
SND_PCM_NONBLOCK: .8byte 0x1 SND_PCM_ASYNC: .8byte 0x2 SND_PCM_STREAM_PLAYBACK: .8byte 0
SND_PCM_FORMAT_U8: .8byte 1 SND_PCM_FORMAT_U16_LE: .8byte 4 SND_PCM_FORMAT_U24_LE: .8byte 8 SND_PCM_FORMAT_U32_LE: .8byte 12 SND_PCM_FORMAT_S8: .8byte 0 SND_PCM_FORMAT_S16_LE: .8byte 2 SND_PCM_FORMAT_S24_LE: .8byte 6 SND_PCM_FORMAT_S32_LE: .8byte 10
SND_PCM_ACCESS_MMAP_INTERLEAVED: .8byte 0 SND_PCM_STATE_PREPARED: .8byte 2
AUDIO_BUFFER_STATE_IDLE: .8byte 0 AUDIO_BUFFER_STATE_WRITING: .8byte 1 AUDIO_BUFFER_STATE_PLAYING: .8byte 2
t1: .8byte 0 t2: .8byte 0
alsa: alsa.pcm_handle: .8byte 0 alsa.hw_params: .8byte 0 alsa.last_error: .8byte 0 alsa.initialized: .8byte 0 alsa.device_name: .ascii "hw:2,0\0"
audio_buffers.count_max: .8byte 16
amd64_audio_last_error: .8byte 0 ```
function:
``` amd64_audio_play:
/* rdi: (input) address to audio data: * (+0/2) audio format (1: PCM, 2: IEEE754) * (+2/2) amount of channels * (+4/4) rate in hertz * (+8/4) bytes per sec (frequency * bytes per block) * (+12/2) bytes per block (number of channels * bits per sample / 8) * (+14/2) bits per sample * (+16/8) total size of samples data * (+24/8) address to samples data */
/* Align stack on 96byte boundary: */
push %r15 mov %rsp, %r15 and $-32, %rsp
mov %rsp, %rax mov $96, %r14 xor %rdx, %rdx div %r14 sub %rdx, %rsp
sub $96, %rsp mov %r15, (%rsp)
/* Store registers: */
sub $192, %rsp call amd64_util_store_gpr_regs
/* Create stack space: */
sub $192, %rsp mov %rdi, (%rsp)
/* stack layout: * (+0/8) rdi (address to audio data) * (+8/8) buffer size (altered by *buffer_size_near) * (+16/8) period size (set when setting period size) * (+24/8) rate in hertz * (+32/8) temp */
xor %r15, %r15 mov 16(%rdi), %r15 mov %r15, 8(%rsp)
xor %r15, %r15 mov 4(%rdi), %r15d mov %r15d, 24(%rsp)
movq $0, 32(%rsp)
/* Open pcm if needed: */
cmpq $0, (alsa.pcm_handle) jne .amd64_audio_play.pcm_is_open
lea alsa.pcm_handle, %rdi mov %rdi, (%rdi) lea alsa.device_name, %rsi mov (SND_PCM_ACCESS_MMAP_INTERLEAVED), %rdx mov (SND_PCM_NONBLOCK), %r10
call snd_pcm_open
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_open
.amd64_audio_play.pcm_is_open:
/* Allocate hw params: */
cmpq $0, (alsa.hw_params) jne .amd64_audio_play.hw_params_are_allocated
lea alsa.hw_params, %rdi mov %rdi, (%rdi)
call snd_pcm_hw_params_malloc
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_malloc
.amd64_audio_play.hw_params_are_allocated:
/* Get all possible combinations into hw params: */
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi
call snd_pcm_hw_params_any
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_any
/* Set access: */
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi mov (SND_PCM_ACCESS_MMAP_INTERLEAVED), %rdx
call snd_pcm_hw_params_set_access
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_set_access
/* Set format: */
xor %rdi, %rdi mov (%rsp), %rdi mov 14(%rdi), %r15w mov (%rdi), %r14w
cmp $1, %r14w jne .amd64_audio_play.error.format_unsupported
cmpw $32, %r15w je .amd64_audio_play.format32 cmpw $24, %r15w je .amd64_audio_play.format24 cmpw $16, %r15w je .amd64_audio_play.format16 cmpw $8, %r15w je .amd64_audio_play.format8 jmp .amd64_audio_play.error.format_unsupported
.amd64_audio_play.format32: mov (SND_PCM_FORMAT_S32_LE), %rdx jmp .amd64_audio_play.format_end
.amd64_audio_play.format24: mov (SND_PCM_FORMAT_S24_LE), %rdx jmp .amd64_audio_play.format_end
.amd64_audio_play.format16: mov (SND_PCM_FORMAT_S16_LE), %rdx jmp .amd64_audio_play.format_end
.amd64_audio_play.format8: mov (SND_PCM_FORMAT_S8), %rdx jmp .amd64_audio_play.format_end
.amd64_audio_play.format_end:
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi
call snd_pcm_hw_params_set_format
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_set_format
/* Set channels: */
xor %rdx, %rdx mov (%rsp), %r15
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi mov 2(%r15), %dx
call snd_pcm_hw_params_set_channels
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_set_channels
/* Set buffer size near: */ /* Returns 0, meaning it succeeded. No crashes generated. */
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi mov %rsp, %rdx add $8, %rdx mov $0, %r10
call snd_pcm_hw_params_set_buffer_size_near
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_set_buffer_size_near
/* Set rate near: */ /* CRASHES */
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi mov %rsp, %rdx add $24, %rdx mov $0, %r10
call snd_pcm_hw_params_set_rate_near
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_set_rate_near
/* Set period size near: */ /* CRASHES */
mov 8(%rsp), %rax mov $4, %r15 xor %rdx, %rdx div %r15 mov %rax, 16(%rsp)
mov (alsa.pcm_handle), %rdi mov (alsa.hw_params), %rsi mov %rsp, %rdx add $16, %rdx mov $0, %r10
call snd_pcm_hw_params_set_period_size_near
cmp $0, %rax jne .amd64_audio_play.error.snd_pcm_hw_params_set_period_size_near
/* Free hw params: */
cmpq $0, (alsa.hw_params) je .amd64_audio_play.hw_params_not_allocated
mov (alsa.hw_params), %rdi
call snd_pcm_hw_params_free
movq $0, (alsa.hw_params)
.amd64_audio_play.hw_params_not_allocated:
/* Register errors: */
xor %rax, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_open: mov %rax, (amd64_audio_last_error) mov $-1, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_malloc: mov %rax, (amd64_audio_last_error) mov $-2, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_any: mov %rax, (amd64_audio_last_error) mov $-3, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_set_access: mov %rax, (amd64_audio_last_error) mov $-4, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.format_unsupported: mov $-5, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_set_format: mov %rax, (amd64_audio_last_error) mov $-6, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_set_channels: mov %rax, (amd64_audio_last_error) mov $-7, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_set_buffer_size_near: mov %rax, (amd64_audio_last_error) mov $-8, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_set_period_size_near: mov %rax, (amd64_audio_last_error) mov $-9, %rax jmp .amd64_audio_play.exit
.amd64_audio_play.error.snd_pcm_hw_params_set_rate_near: mov %rax, (amd64_audio_last_error) mov $-10, %rax jmp .amd64_audio_play.exit
/* Exit: */
.amd64_audio_play.exit:
/* Print error to stdout: */
mov %rax, %rdi call amd64_util_print_dec call amd64_util_print_newline
cmpq $0, (amd64_audio_last_error) je .amd64_audio_play.no_error
mov (amd64_audio_last_error), %rdi call snd_strerror
mov %rax, %rdi call amd64_util_print2 call amd64_util_print_newline
.amd64_audio_play.no_error:
/* Restore stack: */
add $192, %rsp
/* Restore registers without rax: */
mov %rax, 128(%rsp) call amd64_util_restore_gpr_regs mov 128(%rsp), %rax add $192, %rsp
/* Restore stack alignment: */
pop %rsp pop %r15
ret ```
Issue URL : https://github.com/alsa-project/alsa-lib/issues/471 Repository URL: https://github.com/alsa-project/alsa-lib
participants (1)
-
GitHub issues - opened