0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

axxでx86_64のリロケータブルELFを作成そして、リンク・実行まで

0
Last updated at Posted at 2026-03-11

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用ミニマルパターンファイル

hello.axx
.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本体

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)

hel.s
; 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
;
; 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
;
; 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言語ライブラリの呼び出し

clinktest.axx
LEA RDI,[RIP+!s]::0x48,0x8d,0x3d,@@[4,*(s-$$,%%)]
XOR EAX,EAX::0x31,0xc0
CALL !s::0xe8,@@[4,*(s-$$,%%)]
RET::0xc3
clinktest.s
.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 で、シェアードオブジェクトファイル作成

ソース

sotest.s
.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から呼び出す。

main.c
void hello();
int main(void) {
    hello();
}

リンク

gcc main.c -L. -lsotest

実行

LD_LIBRARY_PATH=. a.out
hello

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?