目次: ALSA
一覧が欲しくなったので作りました。
厳密にいうとALSA関係ないですが、PulseAudioやmplayerの話もまとめます。
目次: 車
例年であればGWは実家に帰省していて、GWの首都高の様子なんて興味もなければ知りもしませんでしたが、今年のGWは珍しく実家に帰らなかったんです。
しかもGWの初日の今日、間違えて湾岸線の「下り」に乗ってしまいました。当然ながらエラい渋滞にはまりましたが、併走する下道は空いているようで不思議でした。
ちょっと訳あって朝、昼の2回(高速上り、下り&高速上り、下道の下り)走ったためか、渋滞の傾向が良く見えました。首都高1号と湾岸高速の下りだけ1日中ずっと渋滞していました。湾岸線は北関東ナンバーの車で埋め尽くされていましたが、高速の上りや下道のR357、R15(第一京浜)は空いていました。
別の道、中央道と甲州街道を思い浮かべると、高速も下道もどちらも渋滞しそうなものです。たとえばR15(第一京浜)だって、首都高1号や横羽線とほぼずっと併走していますし、渋滞していそうなものですがめちゃ空いていて意外でした。まあ、大田区から向こうは知らないですけど……。なぜ首都高だけ例外なんでしょう、不思議ですね。
どこから来るかにもよりますが、C2や湾岸線下りの混雑を回避するなら、足立区辺りで降りてR4 → 都内 → R15が下道ルートでしょうか?そうするとですね、
自分がもし北関東から来たお父さんホリデードライバーだとしたら、わざわざ降りるか?というと……まず降りませんね!普段運転しないならなおさら嫌です。都内の道なんか考えたくない、もし迷おうものなら家族のブーイングは必至。面倒です。
というわけで「GW初日の湾岸高速は下りのみ2時間以上の渋滞、上りと、下りに併走する下道はがら空き」という役に立たないクソ知識を体得しました。
超どうでも良い!もう二度と使わなさそう!!
目次: ALSA
はるか昔、もう8年も前に見つけたalsa-libのバグ(2014年7月9日の日記参照)、今日見てもまだ直ってなかったっぽいです。激しくノイズが載ってしまう割と致命的なバグですが、発生条件が珍しくてあまり使われないコードのため、未だに誰も直すモチベーションがないと推測されます。せっかく思い出したので、パッチをぶん投げておきました。
パッチの投稿先がわからなくて困ったのですが、どうもalsa-libはGitHubを(リポジトリへのリンク)使っていて、IssueやPull Request管理しているようです。GitHub使ってるんですね。へー。
ALSAはユーザ空間のalsa-libの他に、カーネル空間のコードもあります。カーネル空間のコードはLinux Kernelの一部として開発されています。Linux KernelはGitHubをコード管理に使っておらず、ミラーだけしています(つまりGitHubのPull RequestやIssueは使わない)。
当然ながらLinux Kernelメンテナ達のリポジトリもGitHubではなくgit.kernel.orgに置かれていることが多いです。ALSAのカーネル側コードも例外ではなくgit.kernel.orgの下に置かれて(リポジトリへのリンク)います。
メモ: 技術系の話はFacebookから転記しておくことにした。合併と加筆。
目次: C言語とlibc
前回はtp(スレッドポインタ)レジスタの初期化を調べました。今回はTLSの初期化を見たいと思います。起動時に値が設定されている変数の初期化に関わる部分です。
初期化関数 __libc_setup_tls() ではtpの指す先(__sbrk() で確保したメモリ領域)も初期化しています。しかしこちらは結構複雑です。大雑把に言うと、
このような処理が行われます。コードも見ておきましょう。
// glibc/csu/libc-start.c
STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char **argv,
#ifdef LIBC_START_MAIN_AUXVEC_ARG
ElfW(auxv_t) *auxvec,
#endif
__typeof (main) init,
void (*fini) (void),
void (*rtld_fini) (void), void *stack_end)
{
//...
# ifdef HAVE_AUX_VECTOR
/* First process the auxiliary vector since we need to find the
program header to locate an eventually present PT_TLS entry. */
# ifndef LIBC_START_MAIN_AUXVEC_ARG
ElfW(auxv_t) *auxvec;
{
char **evp = ev;
while (*evp++ != NULL)
;
auxvec = (ElfW(auxv_t) *) evp;
}
# endif
_dl_aux_init (auxvec); //★これ★
if (GL(dl_phdr) == NULL)
# endif
// glibc/elf/dl-support.c
void
_dl_aux_init (ElfW(auxv_t) *av)
{
//...
_dl_auxv = av;
for (; av->a_type != AT_NULL; ++av)
switch (av->a_type)
{
case AT_PAGESZ:
if (av->a_un.a_val != 0)
GLRO(dl_pagesize) = av->a_un.a_val;
break;
case AT_CLKTCK:
GLRO(dl_clktck) = av->a_un.a_val;
break;
case AT_PHDR:
GL(dl_phdr) = (const void *) av->a_un.a_val; //★これ★
break;
case AT_PHNUM:
GL(dl_phnum) = av->a_un.a_val;
break;
// glibc/csu/libc-tls.c
void
__libc_setup_tls (void)
{
//...
/* Look through the TLS segment if there is any. */
if (_dl_phdr != NULL)
for (phdr = _dl_phdr; phdr < &_dl_phdr[_dl_phnum]; ++phdr)
if (phdr->p_type == PT_TLS)
{
/* Remember the values we need. */
memsz = phdr->p_memsz;
filesz = phdr->p_filesz;
initimage = (void *) phdr->p_vaddr + main_map->l_addr;
align = phdr->p_align;
if (phdr->p_align > max_align)
max_align = phdr->p_align;
break;
}
//...
/* Initialize the TLS block. */
#if TLS_TCB_AT_TP
//...
#elif TLS_DTV_AT_TP //★★RISC-Vではこちらのコードが使われる★★
_dl_static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset; //★★TLSのアドレス★★
main_map->l_tls_offset = tcb_offset;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
_dl_static_dtv[2].pointer.to_free = NULL;
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
memcpy (_dl_static_dtv[2].pointer.val, initimage, filesz); //★★TLSに初期データをコピー★★
PT_TLSタイプのプログラムヘッダーがどこに配置されているか?など調べたい場合は、実行ファイルをreadelfで見るとわかりやすいです。該当するヘッダがある場合は、Type欄がTLSとなるはずです。
Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flags Align LOAD 0x0000000000000000 0x0000000000010000 0x0000000000010000 0x000000000005d944 0x000000000005d944 R E 0x1000 LOAD 0x000000000005e4d0 0x000000000006f4d0 0x000000000006f4d0 0x0000000000002500 0x0000000000007938 RW 0x1000 NOTE 0x0000000000000190 0x0000000000010190 0x0000000000010190 0x0000000000000020 0x0000000000000020 R 0x4 TLS 0x000000000005e4d0 0x000000000006f4d0 0x000000000006f4d0 ★★TLS初期化に使われるセグメント★★ 0x0000000000000020 0x0000000000000068 R 0x8 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 GNU_RELRO 0x000000000005e4d0 0x000000000006f4d0 0x000000000006f4d0 0x0000000000000b30 0x0000000000000b30 R 0x1
PT_TLSが2つある場合はどうなるでしょう?実はPT_TLSは実行ファイルに1つまでなので気にしなくて良いです。プログラムヘッダは同属性のセクションをまとめて1つのセグメントにします。PT_TLSセグメントを1つだけにするには、TLSに関わるセクションを連続して配置する必要があります。
もしTLS関係のセクションを分散させて配置するとリンク時エラーになります。試しにリンカースクリプトを書き換えTLS関係の .tdataと .tbssセクションの間に、TLSと無関係の .dataセクションを挟む形にすると、
riscv64-unknown-linux-gnu/bin/ld: hello: TLS sections are not adjacent: riscv64-unknown-linux-gnu/bin/ld: TLS: .tdata riscv64-unknown-linux-gnu/bin/ld: non-TLS: .data riscv64-unknown-linux-gnu/bin/ld: TLS: .tbss riscv64-unknown-linux-gnu/bin/ld: map sections to segments failed: bad value collect2: error: ld returned 1 exit status make: *** [Makefile:22: hello] エラー1
リンカーに "TLS sections are not adjacent" と怒られました。
< | 2022 | > | ||||
<< | < | 05 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | - | - | - | - |
合計:
本日: