FreeBSDで、axxを使って、x86_64のELFリロケータブルオブジェクトファイルを作り、リンクして実行させることに成功しました。2026年3月12日にpaxxに-oオプション、リロケータブルELF出力機能が付きました。paxxのリロケータブルELF生成はelf64にだけ対応しています。オブジェクト出力としての、リロケータブルELFのelf64生成は特殊解ですが、僕は実機はx86_64マシンしか持っていないので、今の所ひとつだけ。一般のオブジェクトファイル出力は後で考えます。
2026年4月23日に、axxに、.extern,.globalディレクティブが付きました。テストをしました。
.extern label::reloc_typeで、リロケーションタイプを指定できます。
2026年5月3日に、axxのx86_64リロケータブルELF出力が一応完全になりました。
デフォルトリロケーションタイプは、x86-64・ARM・AArch64・RISC-V・PPCに対応しています。
後は、リロケーションタイプを各CPU用に拡張すればよいです。
2026年5月8日に、axxに、.equでリロケーションタイプを指定できるようになりました。
label: .equ <式>::reloc_typeで指定できます。
リロケーションタイプ
abs64,abs32,abs32s,abs16,abs8
pc32,plt32,pc16,pc8
got32,gotpcrel,got64
ELF出力はlinuxにも対応しています。
今のaxx.pyのELF出力は、FreeBSD,Linux for x86_64への特殊解ですが、ELF64のためのリロケーションタイプの自動判別は命令の一般性が損なわれるためしていません。
動作試験環境
FreeBSD,EndeavourOS(Linux)
アセンブル
axx.py hello.axx hello.s -o hello.o
axx.py hello.axx hel.s -o hel.o
リンク
ld hello.o hel.o -o hello
LLVMのリンカも通りました。
ld.lld -o hello hello.o hel.o
実行
% hello
hello, world
hello, world
%
hello用ミニマルパターンファイル
.setsym::EAX::0
.setsym::EDI::7
.setsym::EDX::2
MOV r,!e :: 0xb8|r,e,e>>8,e>>16,e>>24
MOVABS RSI,!e:: 0x48,0xbe,@@[8,*(e,%%)]
SYSCALL :: 0xf,0x5
MOVABS RAX,!e:: 0x48,0xB8,@@[8,*(e,%%)]
CALL RAX :: 0xff,0xd0
CALL !e :: 0xe8,@@[4,*(e-($$+5),%%)]
NOP :: 0x90
RET :: 0xC3
hello.s本体
; axx test example hello world.
; for x86_64 FreeBSD
;
; assemble:
; axx.py hello.axx hello.s -o hello.o
;
.global _hello
.global _hello2
.section .text
_hello:
_hello2:
mov eax, 4 ; sys_write (04)
mov edi, 1 ; stdout (01)
mov edx,len ; length (13)
movabs rsi,msg ; address
syscall
ret
msg: .ascii "hello, world\n"
len: .equ $$ - msg
.endsection
hel.s hello呼び出し用ラッパー(for .extern,.global directive test)
; axx test example hello world.
; for x86_64 FreeBSD
;
.extern _hello::abs64
.extern _hello2
.global _start
.section .text
_start:
nop
call _hello2
movabs rax,_hello
call rax
mov edi,0 ; return 0
mov eax,1
syscall
.endsection
x86-64におけるサイズ別デフォルトリロケーションタイプ:
8バイト: abs64:R_X86_64_64 (タイプ 1)
4バイト: pc32 :R_X86_64_PC32 (タイプ 2)
2バイト: pc16 :R_X86_64_PC16 (タイプ 13)
1バイト: pc8 :R_X86_64_PC8 (タイプ 15)
linuxで動かすには
Linuxで動かす際は、axxにオプション--osabi Linuxを渡し、システムコール番号を変えればうまく行きます。普通、リンカはOSABIまで見てないので、--osabiは渡す必要はないかも。エラーが出たら渡してください。
Linuxは、EndeavourOSで、動作試験をしました。
変換表
;
; FreeBSD system call numbers
;
SYS_exit 1
SYS_read 3
SYS_write 4
SYS_open 5
SYS_close 6
SYS_mmap 477
SYS_munmap 73
SYS_lseek 478
MAP_FLAGS 0x1002 ; MAP_PRIVATE|MAP_ANON (FreeBSD)
;
; Linux system call numbers
;
SYS_exit 60
SYS_read 0
SYS_write 1
SYS_open 2
SYS_close 3
SYS_mmap 9
SYS_munmap 11
SYS_lseek 8
MAP_FLAGS 0x0022 ; MAP_PRIVATE|MAP_ANONYMOUS (Linux)
C言語ライブラリの呼び出し
LEA RDI,[RIP+!s]::0x48,0x8d,0x3d,@@[4,*(s-$$,%%)]
XOR EAX,EAX::0x31,0xc0
CALL !s::0xe8,@@[4,*(s-$$,%%)]
RET::0xc3
.extern puts::plt32 ;axxではこのようにplt32(リロケーションタイプ)を指定する。
.section .text
.global main
main:
lea rdi, [rip+msg]
xor eax, eax
call puts
ret
.section .data
msg:
.asciz "hello\n"
実行
axx clinktest.axx clinktest.s -o clinktest.o
gcc -o testexe clinktest.o -lc
testexe
hello
axx で、シェアードオブジェクトファイル作成
ソース
.extern puts::plt32
.section .text
.global hello
hello:
lea rdi, [rip+msg]
xor eax, eax
call puts
ret
.section .data
msg:
.asciz "hello\n"
.axxファイルは前述のものを使う。
アセンブル
axx.py clinktest.axx sotest.s -o sotest.o
.soファイル生成
ld -shared -o libsotest.so sotest.o
ELF確認
readelf -h libsotest.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 09 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - FreeBSD
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x0
Start of program headers: 64 (bytes into file)
Start of section headers: 1048 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 14
Section header string table index: 13
シンボル確認
nm -D libsotest.so
00000000000001a0 T hello
U puts
Cから呼び出す。
void hello();
int main(void) {
hello();
}
リンク
gcc main.c -L. -lsotest
実行
LD_LIBRARY_PATH=. a.out
hello