Skip to content

Instantly share code, notes, and snippets.

View rui314's full-sized avatar

Rui Ueyama rui314

  • Blue Whale Systems
  • Tokyo
View GitHub Profile
@rui314
rui314 / Dockerfile
Last active September 17, 2019 11:01
FROM ubuntu:latest
RUN apt update && apt install -y gcc make git binutils libc6-dev gdb
RUN adduser --disabled-password --gecos '' user
USER user
WORKDIR /home/user
@rui314
rui314 / cdecl.c
Last active August 14, 2019 04:59
// Copyright (C) 2019 Rui Ueyama
// Licensed under the MIT license
//
// This command parses a C declaration. Here are a few examples:
//
// $ ./cdecl 'int x'
// x: int
//
// $ ./cdecl 'int **const *x'
// x: pointer to const pointer to pointer to int
@rui314
rui314 / newton.md
Created January 17, 2018 20:19
AMラジオを使ってApple Newtonの起動時の問題を直した話 Raw

Apple Newtonの起動時の問題をこの方法(システムバスのノイズをラジオで聞く)でデバグしたことがある。その問題では、最新のフラッシュイメージが、開発用ハードウェアでは起動するのに実機ではまったく動かなかった(なのでLEDやGPIOなども使えなかった)。でも実機に新しいOSイメージをフラッシュすることはできた。

そこで僕は、システムバスに対してそれぞれ異なる動作をする小さなループをいくつか書いて(なのでループの実行中にバスから出るノイズをラジオで聞くとそれぞれ違う音がする)、起動時に実行されるコードの各所にそれを埋め込んで、AMラジオでバスのノイズを聞いてみた。この仕掛けを使って起動時のコードをトレースしていくことで、問題の場所を1時間ほどでみつけることができた。

多分もっとよい方法もあったのだろうけど、でも面白い方法だったと思う。

https://news.ycombinator.com/item?id=16168499

/// Compute the desired OpenMP runtime from the flags provided.
Driver::OpenMPRuntimeKind Driver::getOpenMPRuntime(const ArgList &Args) const {
- StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME);
+ OptValue RuntimeName = CLANG_DEFAULT_OPENMP_RUNTIME;
const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ);
if (A)
- RuntimeName = A->getValue();
-
- auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName)
# 最初になにをやるのかをコメントで書いておくとコードがぐっとわかりやすくなります。
# コードを書いているときは「ここでは〇〇をやろう」と考えながら書いているわけだけど、
# いったんコードになってしまうとそのメタな情報はなくなってしまうので、
# 読者は「結局これは何をやっているのか」というのを推測しながら読むことになってしまいます。
# コメントで意図を説明しておけば推測に頼らずにすむし、変なコードがあっても意図通り
# なのかバグなのか判別がつきやすい。
#
# なおこれはトップレベルのメソッドです。どういうレイアウトがいいかは
# 他にどんなコードがあるかによりますが、元々の例では単体のこのコードしかないので、
# 単純に引数の合計を計算するだけのものにクラスは不要でしょう。

MIPSのABIは変だという話をこないだのシステムプログラミング会でしたら、ややザワッとしたので、なにがおかしいのかというのをちょっとまとめてみました。まとめてみて思いましたが、やっぱりMIPSのELFファイルはちょっと変です。

謎のmixed endianフィールド

これが僕は一番ひどいと思ったものです。

ファイルにマルチバイトの数値を保存するときはエンディアンというものが問題になります。たとえば0xBEEFという2バイトの数を保存するときは、1バイト目にBE、2バイト目にEFを書くか、逆順で書くかは、ただの決まり事でどっちでもいいわけですが、書く側と読む側で認識があっていないと困ります。世の中的にはリトルエンディアン(下位バイトから書く)のが主流ですがビッグエンディアンなシステムもあります。

それがですね、MIPSのELFヘッダのr_infoという64ビットのフィールドはリトルエンディアンでもビッグエンディアンでもない謎なエンコーディングになっています。具体的には下位32ビットが最初にリトルエンディアンで書かれていて、ビッグエンディアンでエンコードされた上位32ビットがそれに続くという構成になっています。つまりリトルエンディアンだとABCD EFGH、ビッグエンディアンだとHGFE DCBAとなるところが、MIPSのmixed endianだとEFGH DCBAというふうにファイルに書かれていることになります。

#include <stdio.h>
#include <stdlib.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define _GNU_SOURCE
#include <fcntl.h>

A C compiler for Brainfuck

I want to share my friend's crazy project because it demonstrates how a simple Turing-machine-like programming language is actually equivalent to usual real-world computers.

I think we all know the theory that all Turing complete programming languages are equivalent in terms of their powers. If languages A and B are Turing complete, A can emulate B and vice versa. But that's not obvious at all. How can a simple programming model like Turing Machine can run "real" programs such as ones that run on a general-purpose PC? If it is possible in theory, it can be demonstrated.

Before
415.548666 task-clock (msec) # 1.000 CPUs utilized ( +- 0.42% )
25 context-switches # 0.061 K/sec ( +- 4.42% )
1 cpu-migrations # 0.002 K/sec ( +- 28.86% )
60,001 page-faults # 0.144 M/sec
1,159,320,437 cycles # 2.790 GHz ( +- 0.42% )
713,987,937 stalled-cycles-frontend # 61.59% frontend cycles idle ( +- 0.68% )
<not supported> stalled-cycles-backend
1,151,611,502 instructions # 0.99 insns per cycle
# 0.62 stalled cycles per insn ( +- 0.02% )