無限遠まで突撃中

ネット日記書きの徒然。

Ubuntu以外でもMikanOSを動かしたい

ゼロからのOS自作入門

ゼロからのOS自作入門

発売されましたね。

さて、「ゼロからのOS自作入門」は想定環境をUbuntuとしていますが、自分のラップトップがArchLinuxなので、これは困った。 ということで何とかして動かしてみます。

標準ライブラリをビルドする

まずは以下のリポジトリをクローンします。

github.com

MikanOSの標準ライブラリはどうやら devenv_src/stdlib/build.sh でビルドできるようです。

mikanos-build/build.sh at master · uchan-nos/mikanos-build · GitHub

リポジトリから大事な部分を引用します。

exe docker cp ${CID}:/usr/local/x86_64-elf ${HOME}/osbook/devenv

SRC=/usr/local/src
DST=${HOME}/osbook/devenv/x86_64-elf
exe docker cp ${CID}:${SRC}/newlib-cygwin/COPYING.NEWLIB ${DST}/LICENSE.newlib
exe docker cp ${CID}:${SRC}/llvm-project/libcxx/LICENSE.TXT ${DST}/LICENSE.libcxx
exe docker cp ${CID}:${SRC}/freetype-2.10.1/docs/FTL.TXT ${DST}/LICENSE.freetype

echo ""
echo "Done. Standard libraries at ${HOME}/osbook/devenv/x86_64-elf"

Docker内部でビルドした成果物を ${HOME}/osbook/devenv にコピーしているので、この部分を書き換えればよさそうです。

こんな感じに書き換え。

exe docker cp ${CID}:/usr/local/x86_64-elf /path/to/mikanos_third_party

SRC=/usr/local/src
DST=/path/to/mikanos_third_party/x86_64-elf
exe docker cp ${CID}:${SRC}/newlib-cygwin/COPYING.NEWLIB ${DST}/LICENSE.newlib
exe docker cp ${CID}:${SRC}/llvm-project/libcxx/LICENSE.TXT ${DST}/LICENSE.libcxx
exe docker cp ${CID}:${SRC}/freetype-2.10.1/docs/FTL.TXT ${DST}/LICENSE.freetype

echo ""
echo "Done. Standard libraries at /path/to/mikanos_third_party/x86_64-elf"

こうすると /path/to/mikanos_third_party/x86_64-elf に成果物ができている、はずです。

mikanos-buildの各種スクリプトを書き換える

次はmikanos-buildに含まれるmikanosのビルドスクリプトを書き換えます。

buildenv.sh

mikanos-build/buildenv.sh at master · uchan-nos/mikanos-build · GitHub

BASEDIR を書き換えればよさそうです。 こんな感じ。

# Usage: source buildenv.sh

BASEDIR="/path/to/mikanos_third_party/x86_64-elf"
export CPPFLAGS="-I$BASEDIR/include/c++/v1 -I$BASEDIR/include -I$BASEDIR/include/freetype2 -nostdlibinc -D__ELF__ -D_LDBL_EQ_DBL -D_GNU_SOURCE -D_POSIX_TIMERS"
export LDFLAGS="-L$BASEDIR/lib"

make_mikanos_image.sh

mikanos-build/make_mikanos_image.sh at master · uchan-nos/mikanos-build · GitHub

edk2のパスに合わせて LOADER_EFI を書き換えます。

edk2は適当な場所にクローンして、 git submodule update --init をしておくとよい。

#!/bin/sh -ex

DEVENV_DIR=$(dirname "$0")
MOUNT_POINT=./mnt

if [ "$DISK_IMG" = "" ]
then
  DISK_IMG=./mikanos.img
fi

if [ "$MIKANOS_DIR" = "" ]
then
  if [ $# -lt 1 ]
  then
      echo "Usage: $0 <day>"
      exit 1
  fi
  MIKANOS_DIR="$HOME/osbook/$1"
fi

LOADER_EFI="/path/to/edk2/Build/MikanLoaderX64/DEBUG_CLANG38/X64/Loader.efi"
KERNEL_ELF="$MIKANOS_DIR/kernel/kernel.elf"

$DEVENV_DIR/make_image.sh $DISK_IMG $MOUNT_POINT $LOADER_EFI $KERNEL_ELF
$DEVENV_DIR/mount_image.sh $DISK_IMG $MOUNT_POINT

.
.
.

mikanos本体の build.sh

最後にmikanos本体の build.sh を書き換えます。

mikanos/build.sh at master · uchan-nos/mikanos · GitHub

${HOME}/osbook/... となっている部分をmikanos-buildをクローンしたパスに書き換えます。

#!/bin/sh -eu

make ${MAKE_OPTS:-} -C kernel kernel.elf

for MK in $(ls apps/*/Makefile)
do
  APP_DIR=$(dirname $MK)
  APP=$(basename $APP_DIR)
  make ${MAKE_OPTS:-} -C $APP_DIR $APP
done

DISK_IMG=./disk.img MIKANOS_DIR=$PWD /path/to/mikanos-build/devenv/make_mikanos_image.sh

if [ "${1:-}" = "run" ]
then
  /path/to/mikanos-build/devenv/run_image.sh ./disk.img
fi

起動

以上のことをして、mikanosのosbook_day30fのルートディレクトリで

APPS_DIR=apps RESOURCE_DIR=resource ./build.sh run

で動作する(はず)。

2020年の「ケツイ~絆地獄たち~」プレイ振り返り

これは WORDIAN Advent Calendar 2020 - Adventar の21日目の記事です。

ケツイ~絆地獄たち~は2002年に稼働開始したCAVEのアーケード弾幕シューティングだが、レトロゲームの移植に定評があるM2がPS4に移植した「ケツイ Deathtiny ~絆地獄たち~」がある。

自分はWORD編集部に加入してからずっとこのゲームをプレイしています*1が、未だワンコインクリアには至っていません。 いつクリアできるんだろ……

2020年のワンコインケツイ

しかし年を追うごとに進めるステージが増えてきました。

今年はステージ4までワンコインで進めるようになりました。 中ボスのカニを倒した後の左にスライドするシーンあたりが限界ですが……

また2019年まではステージ2の中ボスに対してはボムを決めていたのですが、最近はボムを決めないでも切り抜けられるようになりました。

2021年のワンコインケツイに向けて

ステージ5の中ボス撃破までワンコインでいきたいですね。 日々体調を整え、鍛錬を欠かさないようにしたいです。

最終的には

大学を出るまでにはワンコインクリアしたいです。

一日一ケツイ

*1:アケコンでやっています

12月は新生活の季節

これは

WORDIAN Advent Calendar 2020 - Adventar

の13日目の記事です。

引っ越しました

もうすぐ2021年ですね、突撃隊です。 10月あたりに「3年生の終わりには引っ越したいな」と思い不動産屋に行ったら、年内に入居すると1ヶ月フリーレントだと言われてそのまま12/1に新居に入居してしまいました。

洗濯機の水道パッキンが壊れていたり、洗面台の配管から水漏れしたり、無料インターネット完備と言われていたが業者の管理ミスでインターネット未開通だったり*1とトラブルはありますが、概ね快適に過ごせています。

この記事では引っ越しの際に色々ものを買ったりもらったりして調達したものをレヴューしていきたいと思います。 だいたいデスクまわりです。

イカれた品物たちを紹介するぜ!

Flexispotの電動昇降机の足&適当な天板

flexispot.jp

引っ越しを見越して11月に注文して編集部に放置していたのを入居日に回収して新居に導入しました。

重量なんと35kg。重すぎる。 新居が2階だったので良かったですが、これが3階とかだったら死んでいました。

組み立てるのが面倒で入居から1週間くらい放置していましたが、頑張って組み立てたら大変使い心地が良いものでした。 お好みの高さを3つまでメモリに保存できます、自分は

  • 立ってPC作業をするときの高さ
  • 座ってPC作業をするときの高さ
  • 座って書き物をするときの高さ

の3つを保存しています。

天板サイズは140×70cm、モニタ2つ置くと少し手狭です。横を160cmくらいにしてもよかったな……

オフィスバスターズで買ったバロンチェア

こういうところから選ぶ

バロンチェア オカムラ(okamura)オフィスチェア(椅子)の通販|中古格安オフィス家具通販ならオフィスバスターズ

5万くらいで買いました。ヘッド部はないです。

最初はエルゴヒューマンにしようかと思いましたが、身長が高くないと辛いというレヴューを見てバロンチェアにしました。

届いてみると163cmとお世辞にも高くはない自分の身長にぴったりでGood。 アームレストもいい感じの高さまで上がるし、他にも座部が前後に動いたりして楽しいです。

昇降机と組み合わせるとかなり楽に作業ができます*2

ThinkCentre M73

ThinkCentre M73 Small 製品仕様書 | レノボジャパン

新生活ですから新たなマシンが必要です。 CPUはHaswell i7-4790でメモリは16GB乗っています。ストレージはHDD 1TBなので、速さを求める人はSSDに換装する必要があるでしょう。

とりあえずUbuntu Serverのインストールメディアが手元にあったのでインストールしました。 VM牧場にでもして遊びます。

FlexScan 23.5型(くらい)(型番は失念)

研究室が決まってそろそろ論文も読みたい季節、なかなかいいモニタが手に入りました。 解像度は1920×1200です。

縦置きでPDFを表示するとかなりきれいにうつります。 これで論文読むようにすればプリンタ要らずってわけ*3

YAMAHA RTX1200

おなじみルータ。まだ使っていないですが、インターネットが開通した暁には役に立ってくれるでしょう。

NETGEAR GS108T

L2スイッチ。裏の設置用の磁石が錆びていたので取っ払いました。 これもまだ動かしていない。

ZenWiFi AX(XT8)

www.asus.com

祖母宅から余ったからあげると言われて送られてきました*4。 これ使っとけば無線LANは大丈夫やろ。

その他

炊飯器

今日初めて炊いたらうまかった。

冷蔵庫

YAMADA電気ブランドのやつだけど何十年も使う予定はないのでヨシ!

洗濯機

日立製。特に不満なし。 値段が安かった。

充電式ハンディタイプサイクロン掃除機

地味に良かったもの。

取り回しが良く、ごみも簡単に捨てられるのでかなりいいです。 充電もそんな時間かからないっぽい。

コーナンで買った電気ケトル

尿は沸かさないようにしましょう。

これから

まだコンロを買えていないので土日にでも買いに行きます。

*1:半月もネット無いのはつらい

*2:まだインターネットがないのでほとんどできることはないですが……

*3:紙でほしいときは大学で印刷しよう

*4:祖母宅は民宿なので、デカイ

自作OSに役立った本や資料を紹介する

この記事は 自作OS Advent Calendar 2020 - Adventar の4日目の記事です。

自分が今まで読んできた本や資料の中で、自作OSに役に立ったなと思ったものを紹介します。

書籍編

30日でできる!OS自作入門

30日でできる! OS自作入門

30日でできる! OS自作入門

紹介するまでもない有名な本です。 この本で自分は自作OSを始めました。 試行錯誤の過程を踏みながら、最後には立派なOSが出来上がります。

12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

12ステップで作る組込みOS自作入門

こちらはH8マイコン上で動く自作OSを作ります。 x86_64でスレッドのコンテキストスイッチを実装する際に参考になりました。

Xinuオペレーティングシステムデザイン 改訂2版

現実の製品でも使われているXinuと呼ばれるオペレーティングシステムを、ソースコードレベルで解説したものです。 排他制御の実装が記載されている貴重な本です、自分もこの本を参考にセマフォを実装しました。 またコーディングルールなども簡単に解説されていて、統一感のあるきれいなソースコードだなと思いました。 アーキテクチャx86とArmに対応しているので、複数アーキテクチャに対応したい際にも参考になりそうです。 特におすすめです。

リンカ・ローダ実践開発テクニック

ELFについて詳しく書かれた本です。 ブートローダやプログラムローダ、リンカスクリプトを書く際に大変参考になります。

低レベルプログラミング

低レベルプログラミング

低レベルプログラミング

x86_64アーキテクチャ上で自作OSをするなら読むといい本です。 低レイヤを広く取り扱っている(OSだけでなくバイナリ形式なども)ので、ざっと眺めておくと低レイヤでの地雷を回避できる確率が上がります。

Linuxのブートプロセスをみる

Linuxgrubからブートする様子をソースコードを追って見ていく本です。 x86_64で64bitモードまで上げる際の呪文などが乗っているので、初期化処理を書く際に役立つでしょう。 Linuxの勉強にもなります。

web編

Intel SDM

software.intel.com

何回も読むことになるマニュアルです。 これを読めばCPUの仕様はだいたい乗ってます。

osdev.org

wiki.osdev.org

自作OSを作る際の情報が英語でまとまっています。 大変参考になるサイトですが、たまに動かないサンプルコードが混じっているので注意。

osdev-jpのwiki

github.com

こちらは日本語で自作OSを作る上での情報がまとまっています。 なおosdev-jpはslackやメーリスなどもあります。

resea.org

resea.org

nutaさんという方が作っているマイクロカーネルのページです。 reseaは本当にきれいに設計されており、ドキュメントがしっかりまとまっているので大変参考になります。

オペレーティングシステムⅡのページ

www.coins.tsukuba.ac.jp

筑波大学オペレーティングシステム2という授業のページです。 Linuxカーネルをコードリーディングしています。 実際にデータ構造を設計したりする際に参考になるかと思います。

QEMUソースコード

github.com

なにかデバイスの挙動がわからないときに使えるかもしれないQEMUソースコードです。 自分はAHCIを調査する際に(先輩に助けてもらいながら)読みました。 ただあまり細かい部分やマイナーなデバイスは雑なエミュレーションをしている可能性があるのでそこは注意してください。

他にもまだまだありますが

とりあえずパッと思いつくのを上げてみました。 これもいいよ!というものがあったらコメントなどで教えてください。

ld-linux.soと共有ライブラリあたりの雑記

2020/09/28 .interp と動的リンカの部分を追記しました

最近ブログ更新していなかったので、最近知ったこと書きます。

あ、 ld-linux.so とか共有ライブラリとかの概略はしません。 この記事読んでいる人はわかっていると思うので。

.interp と動的リンカ

ELF実行形式には .interp と呼ばれるセクションがある場合があります。

これは動的リンカを指定するためのセクションで、動的リンカがあるパスが文字列として埋め込まれています。

カーネルはこの .interp セクションを見て動的リンカ( ld-linux.so など)をロードします。

実行形式のロードとセグメント

ld-linux.so はELFのプログラムヘッダを読んでセグメントをメモリ上に配置していきますが、プログラムヘッダにセクション情報はありません。 動的リンク動的ロードが必要な共有ライブラリの情報は .dynamic セクション にありますが、どうやってこのセクションがあるセグメントを特定しているのでしょうか。

実はセグメントの中には DYNAMIC と呼ばれる種類のセグメントがあり、プログラムヘッダからセグメント種別を見分けることができます。

Hello, World!プログラムをコンパイルした実行ファイルを readelf -l してみてみると次のようになっています。

$ readelf -W -l hello

Elf file type is DYN (Shared object file)
Entry point 0x1040
There are 11 program headers, starting at offset 64

Program Headers:
  Type           Offset   VirtAddr           PhysAddr           FileSiz  MemSiz   Flg Align
  PHDR           0x000040 0x0000000000000040 0x0000000000000040 0x000268 0x000268 R   0x8
  INTERP         0x0002a8 0x00000000000002a8 0x00000000000002a8 0x00001c 0x00001c R   0x1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x000558 0x000558 R   0x1000
  LOAD           0x001000 0x0000000000001000 0x0000000000001000 0x0001d5 0x0001d5 R E 0x1000
  LOAD           0x002000 0x0000000000002000 0x0000000000002000 0x000120 0x000120 R   0x1000
  LOAD           0x002de8 0x0000000000003de8 0x0000000000003de8 0x000248 0x000250 RW  0x1000
  DYNAMIC        0x002df8 0x0000000000003df8 0x0000000000003df8 0x0001e0 0x0001e0 RW  0x8
  NOTE           0x0002c4 0x00000000000002c4 0x00000000000002c4 0x000044 0x000044 R   0x4
  GNU_EH_FRAME   0x002014 0x0000000000002014 0x0000000000002014 0x000034 0x000034 R   0x4
  GNU_STACK      0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW  0x10
  GNU_RELRO      0x002de8 0x0000000000003de8 0x0000000000003de8 0x000218 0x000218 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .dynamic .got .got.plt .data .bss 
   06     .dynamic 
   07     .note.gnu.build-id .note.ABI-tag 
   08     .eh_frame_hdr 
   09     
   10     .init_array .fini_array .dynamic .got

確かに DYNAMIC タイプのセグメントがあります。

セクションとセグメントのマップ情報を見ても、 DYNAMIC セグメントには .dynamic セクションが入っています。 DYNAIMC セグメントを読みに行けば .dynamic セグメントが解析できるわけですね。

.dynamic セクション

.dynamic セクションのエントリは次のようになっています。

typedef struct
{
    Elf64_Sxword d_tag;
    union {
        Elf64_Xword d_val;
        Elf64_Addr d_ptr;
    } d_un;
} Elf64_Dyn;

extern Elf64_Dyn _DYNAMIC[];

d_tag で情報の種類を、 d_un で情報本体を表します。

d_tagDT_NEEDED タイプのエントリには必要な共有ライブラリ情報が格納されており、 ld-linux.so はこれを読んで共有ライブラリをロードするわけです。 ちなみに DT_NEEDED タイプのエントリの d_un には文字列テーブルのオフセットが記されています。 このオフセットからテーブルを読むとnull終端された文字列が手に入ります。

文字列はどこ

文字列テーブルと言いましたが、これはどこにあるのでしょうか。

これも .dynamic セクションにあって、 DT_STRTAB タイプのエントリを読むと d_un の値が文字列テーブルのアドレスとなっています。

これで無事に共有ライブラリの名前を手に入れた ld-linux.soファイルシステムから共有ライブラリを読み込むわけですね。

ダイレクトマーケティングコーナー

これいいっすよ。

追記は

またします。

酒に酔った

プレモル500ml缶で酔うお手軽ボディは大変よいものでございます、突撃隊です。

疲れからか酒をコンビニで買ってぐいっといっていい気分になったからこんな記事を書いているわけでございます。

将来

どうするんでしょう。 OSいじって就職できるとあんまり思えないし、なんかWebのやつやんなきゃいけないかなあ。

できれば低レイヤ就職したいんですがどうしたもんですかね。

学業

GPAは破滅しているのでどうするか。

院進は今の所したいなあと思っているのですが、推薦はもらえなさそうなので、普通に大学院入試を受ける必要がありそうです。

そもそも親氏は許してくれますかね? 二浪もしているので留年したら割と行かせてもらえなそう。

自由研究

自作OSは最近調子よくて、なんかバリバリ実装しています。

コードレビューしてもらいながら開発しているとたいへん効率がよく、効率がいいです。 fork()とか実装しちゃってるもんね。

ファイルシステム実装までは行きたいですね。

まとめ

以上がお気持ちです。

自作OSのmallocを大きなバイト数でアライメントできるようにしたい

こんにちは、突撃隊です。

コロナで皆さん大変ですが、自分は作業がはかどっています。 なんとも皮肉なもんです。

自作OSのmallocで大きなアライメントを取りたい

タイトルのとおりです。 4KBとか1MBとかのアライメントを取りたいねという話です。

自分の自作OS「minOSv2」では動的メモリ確保にK&R mallocを実装しています。

github.com

mallocの基本構造は らじうむ覚書さんの K&R Malloc解説 を読むと良いです。

以下の文章ではK&R mallocの基本概念はわかっているとします。

mallocのヘッダサイズと16バイトアライメント

minOSv2のmallocヘッダは以下のように定義されています。

minOSv2/mm.h at feature-ext2 · Totsugekitai/minOSv2 · GitHub

struct malloc_header {
    struct malloc_header *next;
    uint64_t size; // This param's unit is sizeof(struct malloc_header).
};

ポインタ型と uint64_t 型の構造体なので、構造体のサイズは16バイトです。

K&R mallocはヘッダのサイズを1単位として扱うので、つまりmallocの単位としては16バイトずつの確保になります。

リンカスクリプトでヒープ領域をアライメントしてあげると、mallocで確保された領域は自動的に16バイトアライメントされていることになります。

16バイトより大きなアライメントを取るには

リンカスクリプトで調整してあげることによって16バイトアライメントが自動的になされることがわかりました。

しかし16バイトより大きいアライメントを取りたいときがあります。

そう、 ハードウェアの操作 をするときです。

AHCIの操作

この前までAHCIデバイスドライバを書くために奮闘していました。

totsugekitai.hatenablog.com

totsugekitai.hatenablog.com

AHCIデバイスドライバを書く際には128Bアライメントや4KBアライメントでメモリを確保する必要があります。

mallocくんは16バイトアライメントは守ってくれますが、それより大きなアライメントは対応していませんので、なんとかしてやる必要があります。

大きなアライメントに対応したメモリ確保をする関数を作る

まず、アライメントを調整するために何バイトmallocする必要があるでしょうか。

size バイトを al バイトでアライメントするときを考えると、 size + al バイト確保してやり、この確保したメモリ上で開始アドレスをいじってやればアライメントを守ったメモリが確保できそうです。

つまりこうすれば解決ですね。

void *not_aligned_allocate = malloc(size + al);
void *aligned_allocate = align(not_aligned_allocate, al);

void *align(void *addr, int align)
{
    uint64_t addr_num = (uint64_t)addr;
    return (void *)(addr_num + (align - (addr_num % align)));
}

freeができない

しかしこのままでは問題があります、freeができないのです。

というのもK&R Mallocのfreeは、引数で受け取ったアドレスの一個手前にmallocヘッダがあると仮定した処理をしています。

今私たちはmallocしたときに返ってきたアドレスを何バイトか後ろにずらして使っていますので、こうすることはできないのです。

free(aligned_allocate);

何バイトずらしたか情報をもたせたい

何らかの手を考える必要があります。

私たちが知りたいのは何バイトずらしたかという情報です。 この情報さえあれば、大きくアライメントされていても元に戻すことができます。

ここで考えてみると、mallocは16バイトごとにメモリを確保し、そして16バイトより大きくアライメントされているときには、 最低でも16バイトは元の確保したメモリの先頭アドレスからずらしているはずです(ここでは2の累乗バイトアライメントを考えています)。

ということはアライメントした後のアドレスからアドレスが小さい方向に16バイトは何にも使われないことになります。

そういうわけでここに情報を書き込んじゃいましょう。

こちらがソースコードになります。

void *kmalloc_alignas(int size, int align_size)
{
    void *tmp = kmalloc(size + align_size);
    if (is_aligned(tmp, align_size)) {
        return tmp;
    } else {
        void *true_ptr = align(tmp, align_size);
        uint64_t diff = (uint64_t)true_ptr - (uint64_t)tmp;
        putsn_serial("malloc align diff: ", diff);
        ((uint64_t *)true_ptr)[-1] = diff;
        strcpy(&((char *)true_ptr)[-16], "ALIGNED");
        return true_ptr;
    }
}

void kfree_aligned(void *ptr, int align_size)
{
    if ((unsigned long)align_size <= sizeof(struct malloc_header)) {
        kfree(ptr);
    } else {
        if (strcmp(&((char *)ptr)[-16], "ALIGNED") == 0) {
            uint64_t diff = ((uint64_t *)ptr)[-1];
            void *true_ptr = (void *)((char *)ptr - diff);
            putsn_serial("kfree addr diff: ", diff);
            putsp_serial("kfree true free address point: ", true_ptr);
            kfree(true_ptr);
        } else {
            kfree(ptr);
        }
    }
}

kmalloc_alignasとkfree_alignedという関数を作りました。

まずkmalloc_alignasでは、kmallocで確保したメモリ領域のアライメントがあっているかチェックし、あっていたらそのままリターンします。 あっていなかったら、アライメントした後のアドレスの前8バイトにアライメントのために移動させた差の値を書き込みます。

またアライメントした後のアドレスの前16バイトから前9バイトにかけて "ALIGNED" という識別子を置きました。

kfree_alignedでは、まずアライメントサイズを確認し、16バイト以下だったらずらされていないので普通にfreeします。

16バイトより大きい場合、アライメントのためにずらされているかどうかを "ALIGNED" の識別子があるはずの部分を見て判断します。 識別子があったらずらされていると判断し、アライメントのためにどれだけずらされたかを差の値があるはずの部分を読んで計算し直し、mallocヘッダが読み込まれるようにアドレスを調整してからfreeします。

いかがでしたか?

アライメントはたいへんですね、そういえばアライメントの話だとこんな記事もあります。

uchan.hateblo.jp

いや〜アライメントはたいへんですね、気をつけましょう。