# Copyright (C) 2026 Sebastian G. Kirmayer # # This file is part of sysf-i386. # # sysf-i386 is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # sysf-i386 is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along # with sysf-i386. If not, see . # LC_ALL=POSIX _asm_cc() { _asm_ccval=0 for _asm_ccs in o no "b c nae" "nb nc ae" "e z" "ne nz" "be na" "nbe a" \ s ns "p pe" "np po" "l nge" "nl ge" "le ng" "nle g" do for _asm_cc in $_asm_ccs do eval "$1$_asm_cc() { _asm_$1 $_asm_ccval \"\$@\" ; }" done : $(( _asm_ccval += 1 )) done } addl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in imm/reg|imm/mem) if [ $(( -0x80 <= _asm_src_imm && _asm_src_imm < 0x80 )) != 0 ] then byte 0x83 _asm_modrm 0 _asm_dst byte $_asm_src_imm elif [ $_asm_dst = reg ] && [ $_asm_dst_reg = 0 ] then byte 0x05 long $_asm_src_imm else byte 0x81 _asm_modrm 0 _asm_dst long $_asm_src_imm fi ;; reg/reg|reg/mem) byte 0x01 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x03 _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "addl $_asm_src $_asm_dst: unsupported" esac } andl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst/$_asm_dst_reg in imm/reg/0) byte 0x25 long $_asm_src_imm ;; imm/reg/*|imm/mem/*) byte 0x81 _asm_modrm 4 _asm_dst long $_asm_src_imm ;; reg/reg/*|reg/mem/*) byte 0x21 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg/*|mem/reg/*) byte 0x23 _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "andl $_asm_src $_asm_dst: unsupported" esac } cmpb() { _asm_src8 "$1" _asm_dst8 "$2" case $_asm_src/$_asm_dst/$_asm_dst_reg in imm/reg/0) byte 0x3C byte $_asm_src_imm ;; imm/reg/*|imm/mem/*) byte 0x80 _asm_modrm 7 _asm_dst byte $_asm_src_imm ;; reg/reg|reg/mem) byte 0x38 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x3A _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "cmpb $_asm_src $_asm_dst: unsupported" esac } cmpl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in imm/reg|imm/mem) if [ $(( -0x80 <= _asm_src_imm && _asm_src_imm < 0x80 )) != 0 ] then byte 0x83 _asm_modrm 7 _asm_dst byte $_asm_src_imm elif [ $_asm_dst = reg ] && [ $_asm_dst_reg = 0 ] then byte 0x3D long $_asm_src_imm else byte 0x81 _asm_modrm 7 _asm_dst long $_asm_src_imm fi ;; reg/reg|reg/mem) byte 0x39 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x3B _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "cmpl $_asm_src $_asm_dst: unsupported" esac } cmpsb() { byte 0xA6 } call() { _asm_dst "$1" case $_asm_dst in reg|mem) byte 0xFF _asm_modrm 2 _asm_dst return ;; imm) ;; *) _asm_panic "call $_asm_dst: unsupported" esac _asm_jmp_dist=$(( _asm_dst_imm - _asm_offset )) byte 0xE8 long $((_asm_jmp_dist-5)) } _asm_cc cmov _asm_cmov() { _asm_src "$2" _asm_dst "$3" case $_asm_src/$_asm_dst in reg/reg|mem/reg) byte 0x0F byte $(( 0x40 | $1 )) _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "cmov $_asm_src $_asm_dst: unsupported" esac } decl() { _asm_dst "$1" case $_asm_dst in reg) byte $(( 0x48 | _asm_dst_reg )) ;; reg|mem) byte 0xFF _asm_modrm 1 _asm_dst ;; *) _asm_panic "decl $_asm_dst: unsupported" esac } divl() { _asm_src "$1" case $_asm_src in reg|mem) byte 0xF7 _asm_modrm 6 _asm_src ;; *) _asm_panic "divl $_asm_src: unsupported" esac } incl() { _asm_dst "$1" case $_asm_dst in reg) byte $(( 0x40 | _asm_dst_reg )) ;; reg|mem) byte 0xFF _asm_modrm 0 _asm_dst ;; *) _asm_panic "incl $_asm_dst: unsupported" esac } incb() { _asm_dst8 "$1" case $_asm_dst in reg|mem) byte 0xFE _asm_modrm 0 _asm_dst ;; *) _asm_panic "incb $_asm_dst: unsupported" esac } int() { byte 0xCD byte "$1" } int3() { byte 0xCC } _asm_cc j _asm_j() { _asm_eval "$2" _asm_jmp_dist=$(( _asm_value - _asm_offset )) if [ $(( -0x80 <= _asm_jmp_dist-2 && _asm_jmp_dist-2 < 0x80 )) != 0 ] then byte $(( 0x70 | $1 )) byte $((_asm_jmp_dist-2)) else byte 0x0F byte $(( 0x80 | $1 )) long $((_asm_jmp_dist-6)) fi } jmp() { _asm_dst "$1" case $_asm_dst in reg|mem) byte 0xFF _asm_modrm 4 _asm_dst return ;; imm) ;; *) _asm_panic "jmp $_asm_dst: unsupported" esac _asm_jmp_dist=$(( _asm_dst_imm - _asm_offset )) if [ $(( -0x80 <= _asm_jmp_dist-2 && _asm_jmp_dist-2 < 0x80 )) != 0 ] then byte 0xEB byte $((_asm_jmp_dist-2)) else byte 0xE9 long $((_asm_jmp_dist-5)) fi } leal() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in mem/reg) byte 0x8D _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "leal $_asm_src $_asm_dst: unsupported" esac } movb() { _asm_src8 "$1" _asm_dst8 "$2" case $_asm_src/$_asm_dst in reg/reg|reg/mem) byte 0x88 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x8A _asm_modrm $_asm_dst_reg _asm_src ;; imm/reg) byte $(( 0xB0 | _asm_dst_reg )) byte $_asm_src_imm ;; imm/reg|imm/mem) byte 0xC6 _asm_modrm 0 _asm_dst byte $_asm_src_imm ;; *) _asm_panic "movb $_asm_src $_asm_dst: unsupported" esac } movl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in reg/reg|reg/mem) byte 0x89 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x8B _asm_modrm $_asm_dst_reg _asm_src ;; imm/reg) byte $(( 0xB8 | _asm_dst_reg )) long $_asm_src_imm ;; imm/reg|imm/mem) byte 0xC7 _asm_modrm 0 _asm_dst long $_asm_src_imm ;; *) _asm_panic "movl $_asm_src $_asm_dst: unsupported" esac } mull() { _asm_src "$1" case $_asm_src in reg|mem) byte 0xF7 _asm_modrm 4 _asm_src ;; *) _asm_panic "mull $_asm_src: unsupported" esac } negl() { _asm_dst "$1" case $_asm_dst in reg|mem) byte 0xF7 _asm_modrm 3 _asm_dst ;; *) _asm_panic "negl $_asm_dst: unsupported" esac } nop() { byte 0x90 } notl() { _asm_dst "$1" case $_asm_dst in reg|mem) byte 0xF7 _asm_modrm 2 _asm_dst ;; *) _asm_panic "notl $_asm_dst: unsupported" esac } orl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in imm/reg|imm/mem) if [ $(( -0x80 <= _asm_src_imm && _asm_src_imm < 0x80 )) != 0 ] then byte 0x83 _asm_modrm 1 _asm_dst byte $_asm_src_imm elif [ $_asm_dst = reg ] && [ $_asm_dst_reg = 0 ] then byte 0x0D long $_asm_src_imm else byte 0x81 _asm_modrm 1 _asm_dst long $_asm_src_imm fi ;; reg/reg|reg/mem) byte 0x09 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x0B _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "orl $_asm_src $_asm_dst: unsupported" esac } orb() { _asm_src8 "$1" _asm_dst8 "$2" case $_asm_src/$_asm_dst in imm/reg|imm/mem) if [ $_asm_dst = reg ] && [ $_asm_dst_reg = 0 ] then byte 0x0C long $_asm_src_imm else byte 0x80 _asm_modrm 1 _asm_dst long $_asm_src_imm fi ;; reg/reg|reg/mem) byte 0x08 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x0A _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "orb $_asm_src $_asm_dst: unsupported" esac } popl() { _asm_dst "$1" case $_asm_dst in reg) byte $((0x58 | _asm_dst_reg)) ;; reg|mem) byte 0x8F _asm_modrm 0 _asm_dst ;; *) _asm_panic "popl $_asm_src: unsupported" esac } pushl() { _asm_src "$1" case $_asm_src in reg) byte $((0x50 | _asm_src_reg)) ;; reg|mem) byte 0xFF _asm_modrm 6 _asm_src ;; imm) byte 0x68 long $_asm_src_imm ;; *) _asm_panic "pushl $_asm_src: unsupported" esac } repnz() { byte 0xF2 "$@" } repz() { byte 0xF3 "$@" } ret() { if [ $# -eq 0 ] then byte 0xC3 else byte 0xC2 word "$1" fi } scasb() { byte 0xAE } shll() { _asm_src8 "$1" _asm_dst "$2" case $_asm_src/$_asm_src_reg/$_asm_dst in imm/*/reg|imm/*/mem) if [ $_asm_src_imm = 1 ] ; then byte 0xD1 _asm_modrm 4 _asm_dst else byte 0xC1 _asm_modrm 4 _asm_dst byte $_asm_src_imm fi ;; reg/1/reg|reg/1/mem) byte 0xD3 _asm_modrm 4 _asm_dst ;; *) _asm_panic "shll $_asm_src $_asm_dst: unsupported" esac } shrl() { _asm_src8 "$1" _asm_dst "$2" case $_asm_src/$_asm_src_reg/$_asm_dst in imm/*/reg|imm/*/mem) if [ $_asm_src_imm = 1 ] ; then byte 0xD1 _asm_modrm 5 _asm_dst else byte 0xC1 _asm_modrm 5 _asm_dst byte $_asm_src_imm fi ;; reg/1/reg|reg/1/mem) byte 0xD3 _asm_modrm 5 _asm_dst ;; *) _asm_panic "shrl $_asm_src $_asm_dst: unsupported" esac } subl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in imm/reg|imm/mem) if [ $(( -0x80 <= _asm_src_imm && _asm_src_imm < 0x80 )) != 0 ] then byte 0x83 _asm_modrm 5 _asm_dst byte $_asm_src_imm elif [ $_asm_dst = reg ] && [ $_asm_dst_reg = 0 ] then byte 0x2D long $_asm_src_imm else byte 0x81 _asm_modrm 5 _asm_dst long $_asm_src_imm fi ;; reg/reg|reg/mem) byte 0x29 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x2B _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "subl $_asm_src $_asm_dst: unsupported" esac } test() { _asm_panic "test requires width suffix" } testl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst/$_asm_dst_reg in imm/reg/0) byte 0xA9 long $_asm_src_imm ;; imm/reg/*|imm/mem/*) byte 0xF7 _asm_modrm 0 _asm_dst long $_asm_src_imm ;; reg/reg/*|reg/mem/*) byte 0x85 _asm_modrm $_asm_src_reg _asm_dst ;; *) _asm_panic "testl $_asm_src $_asm_dst: unsupported" esac } ud2() { byte 0x0F byte 0x0B } xchgl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst/$_asm_src_reg/$_asm_dst_reg in reg/reg/0/*) byte $((0x90 + _asm_dst_reg)) ;; reg/reg/*/0) byte $((0x90 + _asm_src_reg)) ;; reg/reg/*|mem/reg/*) byte 0x87 _asm_modrm $_asm_dst_reg _asm_src ;; reg/reg/*|reg/mem/*) byte 0x87 _asm_modrm $_asm_src_reg _asm_dst ;; *) _asm_panic "xchgl $_asm_src $_asm_dst: unsupported" esac } xorl() { _asm_src "$1" _asm_dst "$2" case $_asm_src/$_asm_dst in imm/reg|imm/mem) if [ $(( -0x80 <= _asm_src_imm && _asm_src_imm < 0x80 )) != 0 ] then byte 0x83 _asm_modrm 6 _asm_dst byte $_asm_src_imm elif [ $_asm_dst = reg ] && [ $_asm_dst_reg = 0 ] then byte 0x35 long $_asm_src_imm else byte 0x81 _asm_modrm 6 _asm_dst long $_asm_src_imm fi ;; reg/reg|reg/mem) byte 0x31 _asm_modrm $_asm_src_reg _asm_dst ;; reg/reg|mem/reg) byte 0x33 _asm_modrm $_asm_dst_reg _asm_src ;; *) _asm_panic "xorl $_asm_src $_asm_dst: unsupported" esac } byte() { : $(( _asm_offset += 1 )) _asm_eval "$1" _asm_printf "\\$(printf %03o $(( _asm_value & 0xFF )))" } word() { _asm_eval "$1" _asm_word=$_asm_value byte $(( _asm_word )) byte $(( _asm_word >> 8 )) } long() { _asm_eval "$1" _asm_long=$_asm_value word $(( _asm_long )) word $(( _asm_long >> 16 )) } align() { _asm_align=${1-4} skip $(( (_asm_align - (_asm_offset % _asm_align)) % _asm_align )) } skip() { _asm_eval "$1" : $(( _asm_offset += _asm_value )) if [ $_asm_active != 0 ] ; then while [ $_asm_value -gt 0 ] ; do printf '\0' : $(( _asm_value -= 1 )) done fi } ascii() { : $(( _asm_offset += ${#1} )) _asm_printf '%s' "$1" } _asm_modrm() { eval "_asm_modrm_rm=\$$2" case $_asm_modrm_rm in reg) byte $(( 0xC0 | $1 << 3 | $2_reg )) return ;; mem) ;; *) _asm_panic "modrm $_asm_modrm_rm: unsupported" esac for part in base index scale displ ; do eval "_asm_modrm_$part=\$$2_mem_$part" done if [ -z "$_asm_modrm_displ" ] && [ "$_asm_modrm_base" != 5 ] ; then _asm_modrm_displsize=0 elif [ $(( -128 <= _asm_modrm_displ && _asm_modrm_displ < 128 )) != 0 ] then _asm_modrm_displsize=1 else _asm_modrm_displsize=2 fi if [ -z "$_asm_modrm_index" ] && [ "$_asm_modrm_base" != 4 ] ; then if [ -z "$_asm_modrm_base" ] ; then byte $(( $1 << 3 | 5 )) _asm_modrm_displsize=2 else byte $(( _asm_modrm_displsize << 6 | $1 << 3 | _asm_modrm_base )) fi else if [ -z "$_asm_modrm_base" ] ; then byte $(( $1 << 3 | 4 )) _asm_modrm_displsize=2 _asm_modrm_base=5 else byte $(( _asm_modrm_displsize << 6 | $1 << 3 | 4 )) fi [ "$_asm_modrm_index" ] || _asm_modrm_index=4 byte $(( _asm_modrm_scale << 6 | _asm_modrm_index << 3 | _asm_modrm_base )) fi case $_asm_modrm_displsize in 0) ;; 1) byte $((_asm_modrm_displ)) ;; 2) long $((_asm_modrm_displ)) ;; esac } _asm_src8() { _asm_op8 "$1" "_asm_src$2" } _asm_src() { _asm_op "$1" "_asm_src$2" } _asm_dst8() { _asm_op8 "$1" _asm_dst } _asm_dst() { _asm_op "$1" _asm_dst } _asm_op8() { case "$1" in %*) eval "$2=reg" _asm_register8 "${1#%}" "$2_reg" ;; @*) eval "$2=mem" _asm_memory "${1#@}" "$2_mem" ;; *) eval "$2=imm" _asm_eval "$1" eval "$2_imm=\$_asm_value" esac } _asm_op() { case "$1" in %*) eval "$2=reg" _asm_register "${1#%}" "$2_reg" ;; @*) eval "$2=mem" _asm_memory "${1#@}" "$2_mem" ;; *) eval "$2=imm" _asm_eval "$1" eval "$2_imm=\$_asm_value" esac } _asm_register8() { case "$1" in al) eval "$2=0" ;; cl) eval "$2=1" ;; dl) eval "$2=2" ;; bl) eval "$2=3" ;; ah) eval "$2=4" ;; ch) eval "$2=5" ;; dh) eval "$2=6" ;; bh) eval "$2=7" ;; *) _asm_panic "unknown register %$1" esac } _asm_register() { case "$1" in eax) eval "$2=0" ;; ecx) eval "$2=1" ;; edx) eval "$2=2" ;; ebx) eval "$2=3" ;; esp) eval "$2=4" ;; ebp) eval "$2=5" ;; esi) eval "$2=6" ;; edi) eval "$2=7" ;; *) _asm_panic "unknown register %$1" esac } _asm_memory() { _asm_memory_base= _asm_memory_index= _asm_memory_scale= _asm_memory_displ= _asm_memory_arg="$1+" while [ "$_asm_memory_arg" ] ; do _asm_memory_head="${_asm_memory_arg%%+*}" _asm_memory_arg="${_asm_memory_arg#*+}" case "$_asm_memory_head" in %*) if [ -z "$_asm_memory_base" ] ; then _asm_register "${_asm_memory_head#%}" _asm_memory_base elif [ -z "$_asm_memory_index" ] ; then _asm_register "${_asm_memory_head#%}" _asm_memory_index _asm_memory_scale=0 else _asm_panic "more than two registers in address calculation" fi ;; [1248]%*) if [ -z "$_asm_memory_index" ] ; then _asm_register "${_asm_memory_head#[1248]%}" _asm_memory_index _asm_memory_scale1=0 _asm_memory_scale2=1 _asm_memory_scale4=2 _asm_memory_scale8=3 : $(( _asm_memory_scale = _asm_memory_scale${_asm_memory_head%%\%*} )) else _asm_panic "two index registers in address calculation" fi ;; *%*) _asm_panic "illegal scale ${_asm_memory_head%%\%}" ;; *) _asm_eval "$_asm_memory_head" if [ -z "$_asm_memory_displ" ] ; then _asm_memory_displ="$_asm_value" else _asm_panic "two displacements in address calculation" fi esac done [ "$_asm_memory_index" != 4 ] || _asm_panic "cannot use %esp as index" for part in base index scale displ ; do eval "$2_$part=\"\$_asm_memory_$part\"" done } _asm_eval() { _asm_dropminus="${1#-}" case "$_asm_dropminus" in 0x*) case "${_asm_dropminus#0x}" in *[!0-9A-Fa-f]*) ;; *) : $(( _asm_value = $1 )) return esac ;; 0*) case "$_asm_dropminus" in *[!0-7]*) ;; *) : $(( _asm_value = $1 )) return esac ;; *[!0-9]*) ;; *) : $(( _asm_value = $1 )) return esac case "$1" in [!a-zA-Z_]*|*[!a-zA-Z0-9_]*) ;; *) eval "_asm_value=\$_asm_label_$1" if [ "$_asm_value$_asm_pass0" = "" ] ; then _asm_panic "label $1 not declared" fi : $(( _asm_value = _asm_value )) return esac case "$1" in *^|*.) _asm_eval_L="${1%[.^]}" _asm_L $_asm_eval_L : $(( _asm_eval_L_idx = _asm_L_${_asm_eval_L}_idx )) case "$1" in *.) : $(( _asm_eval_L_idx += 1 )) esac eval "_asm_value=\$_asm_L_${_asm_eval_L}_${_asm_eval_L_idx}" if [ "$_asm_value$_asm_pass0" = "" ] ; then _asm_panic "label $1 not declared" fi : $(( _asm_value = _asm_value )) return esac _asm_panic "failed to parse value $1" } _asm_panic() { printf '%s\n' "$@" >&2 exit 1 } _asm_printf() { if [ $_asm_active != 0 ] ; then printf "$@" ; fi } _asm_start_elf=0 _asm_mmap_min_addr=0x10000 _asm_flags_text=0x1 # x _asm_flags_rodata=0x4 # r _asm_flags_data=0x6 # rw _asm_section() { : $(( _asm_offset_$_asm_section = _asm_offset )) _asm_section="$1" : $(( _asm_offset = _asm_offset_$_asm_section )) : $(( _asm_active = _asm_active_$_asm_section )) } text() { _asm_section text ; } rodata() { _asm_section rodata ; } data() { _asm_section data ; } bss() { _asm_section bss ; } _asm_set() { : $(( _asm_set_new = ($2) )) : $(( _asm_modified |= $1 != _asm_set_new )) : $(( $1 = _asm_set_new )) } label() { eval "_asm_label_oldval=\$_asm_label_$1" if [ "$_asm_pass0" ] && [ "$_asm_label_oldval" ] ; then _asm_panic "redefinition of label $1" fi if [ $# -eq 1 ] then _asm_set _asm_label_$1 _asm_offset else _asm_eval "$2" _asm_set _asm_label_$1 '_asm_offset - _asm_value' fi } _asm_L() { [ $(( _asm_generation == _asm_L_$1_gen )) != 0 ] || { : $(( _asm_L_$1_gen = _asm_generation )) : $(( _asm_L_$1_idx = 0 )) } } L() { _asm_L $1 _asm_set _asm_L_$1_$((_asm_L_$1_idx += 1)) _asm_offset } _asm_elf() { _asm_section elf byte 0x7F # magic number ascii 'ELF' byte 1 # 32-bit format byte 1 # little endian byte 1 # ELF version byte 3 # Linux skip 8 # padding word 2 # executable word 3 # x86 long 1 # ELF version long _start # entry point long _asm_phoff # program header offset long 0 # section header offset long 0 # flags word _asm_elfhdr_end # ELF header size word 32 # program header entry size word 4 # program header entry count word 0 # section header entry size word 0 # section header entry count word 0 # section name string table index label _asm_elfhdr_end label _asm_phoff for _asm_local_section in text rodata data ; do : $(( _asm_local_section_length = _asm_end_$_asm_local_section - _asm_start_$_asm_local_section )) long 1 # PT_LOAD long $(( _asm_foffset_$_asm_local_section )) # file offset long $(( _asm_start_$_asm_local_section )) # virtual address long 0 # physical address long $_asm_local_section_length # size in file if [ $_asm_local_section = data ] then long $(( _asm_end_bss - _asm_start_data )) else long $_asm_local_section_length # size in memory fi long $(( _asm_flags_$_asm_local_section )) # permission flags long 0x1000 # alignment done # The PT_GNU_STACK segment is needed to avoid the kernel's # read-implies-exec personality. long 0x6474e551 # PT_GNU_STACK long 0 # file offset long 0 # virtual address long 0 # physical address long 0 # size in file long 0 # size in memory long 0x6 # read/write long 0x1000 # alignment } _asm_run() { for _asm_local_section in elf text rodata data bss ; do : $(( _asm_offset_$_asm_local_section = _asm_start_$_asm_local_section )) : $(( _asm_active_$_asm_local_section = 0 )) done for _asm_local_section in "$@" ; do : $(( _asm_active_$_asm_local_section = 1 )) done _asm_section=text : $(( _asm_offset = _asm_offset_$_asm_section )) : $(( _asm_active = _asm_active_$_asm_section )) _asm_modified=0 : $(( _asm_generation += 1 )) _asm_elf text prog : $(( _asm_offset_$_asm_section = _asm_offset )) _asm_set _asm_end_elf _asm_offset_elf : $(( _asm_offset = _asm_end_elf + _asm_mmap_min_addr )) for _asm_local_section in text rodata data bss ; do : $(( _asm_offset2 = _asm_offset + (_asm_offset_$_asm_local_section - _asm_start_$_asm_local_section) )) _asm_set _asm_start_$_asm_local_section _asm_offset _asm_set _asm_end_$_asm_local_section _asm_offset2 _asm_offset="$_asm_offset2" [ "$_asm_local_section" = data ] || \ : $(( _asm_offset += 0x1000 )) done _asm_foffset=0 for _asm_local_section in elf text rodata data ; do _asm_set _asm_foffset_$_asm_local_section _asm_foffset : $(( _asm_foffset = _asm_foffset + (_asm_end_$_asm_local_section - _asm_start_$_asm_local_section) )) done } _asm_pass0=y _asm_run _asm_pass0= _asm_limit=20 while [ $_asm_modified -eq 1 ] ; do _asm_run : $(( _asm_limit -= 1 )) if [ $_asm_limit -eq 0 ] ; then _asm_panic "pass limit exceeded, failed to converge" fi done _asm_file_offset=0 for _asm_top_section in elf text rodata data ; do _asm_run $_asm_top_section done