.data
x86-64 arch で位置に依存しない方法で sectionから変数にアクセスできる GAS 構文を使用して、 32 ビットarch と IS (%eip
の代わりに) を適用するアセンブリ プログラムを作成しようとしています%rip
。
どのレジスタを試しても、得られた最良の結果は であり、Segmentation fault: 11
それでさえ、まったく実行できないはずの EIP、つまり SF にアクセスするためのものでした。少なくとも「まあ、それはうまくいかない」以外のことを教えてくれたので、最良の結果です。
私はgcc
macOS 10.13.6 mid 2010 Intel Core 2 Duo でファイルをコンパイルしています (それがclang
おそらく理由です):
$ gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
これを使用して、いくつかのオプションをリンカーに渡します。
gcc -m32 -Wl,-fatal_warnings,-arch_errors_fatal,-warn_commons,-pie test.s
ld: 警告: PIE が無効になっています。絶対アドレス指定 (おそらく -mdynamic-no-pic) は、コード署名された PIE では許可されていませんが、/whatever.../test-a07cf9.o の _main で使用されています。この警告を修正するには、-mdynamic-no-pic を使用してコンパイルしたり、-Wl、-no_pie を使用してリンクしたりしないでください。ld: 致命的な警告によってエラーが発生しました (-fatal_warnings)。 -v 呼び出しを表示します) 1
test.s
.text
.global _main
_main:
xor %eax, %eax
xor %ebx, %ebx
# lea var1(%esi/edi/ebp/esp), %ebx # can't compile, not PIE
# lea var1(%eip), %ebx # segfault, obvs
# lea (%esp), %ebx # EBX = 17
# lea (%non-esp), %ebx # segfault
# lea 0(%esi), %ebx # segfault
# lea 0(%edi), %ebx # segfault
# lea 0(%ebp), %ebx # EBX = 0
# lea 0(%esp), %ebx # EBX = 17
# lea 0(%eip), %ebx # segfault, obvs
movl (%ebx), %eax
ret
.data
var1: .long 6
.end
./a.out; echo $?
最後からEAX値を確認するために実行していますret
。
さまざまな情報源を調べましたが、ほとんどはインテルの構文またはこれらの質問の1、2、3です。私が思いついた最も単純なCの例、つまりグローバル変数 +return
からmain()
-を逆アセンブルしようとしましたgcc -S test.c -fPIE -pie -fpie -m32
:
int var1 = 6;
int main() { return var1; }
基本的に次の結果になりました。
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 13
.globl _main ## -- Begin function main
.p2align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushl %ebp
Lcfi0:
.cfi_def_cfa_offset 8
Lcfi1:
.cfi_offset %ebp, -8
movl %esp, %ebp
Lcfi2:
.cfi_def_cfa_register %ebp
pushl %eax
calll L0$pb
L0$pb:
popl %eax
movl $0, -4(%ebp)
movl _var1-L0$pb(%eax), %eax
addl $4, %esp
popl %ebp
retl
.cfi_endproc
## -- End function
.section __DATA,__data
.globl _var1 ## @var1
.p2align 2
_var1:
.long 6 ## 0x6
.subsections_via_symbols
これは明らかにMOVをLEAとして使用し、私のものとほぼ同じ命令を使用しますが、セクションに入るために-L0$pb
+/-のようなアドレスの_var1
-アドレスの部分を除きます。L0$pb
.data
var1
それでも、_main
ラベルと同じアプローチを試してみると、何もありません:
.text
.global _main
_main:
xor %eax, %eax
xor %ebx, %ebx
#movl var1-_main(%ebp), %eax # EAX = 191
#movl var1-_main(%esp), %eax # EAX = 204
#movl var1-_main(%eax), %eax # segfault
ret
.data
var1: .long 6
.end
私が間違っていることは何ですか?
編集:
逆アセンブルされた C の例から不要なものを切り取り、最終的には次のようになりました。
.text
.global _main
_main:
pushl %ebp
pushl %eax
calll test
test:
popl %eax
/* var1, var2, ... */
movl var1-test(%eax), %eax
addl $4, %esp
popl %ebp
retl
/**
* how var1(label) - test(label) skips this label
* if it's about address subtracting?
*/
blobbbb:
xor %edx, %edx
.data
var1: .long 6
var2: .long 135
このガイドによると、呼び出し元は 1) パラメータをスタックにプッシュする (なし) 2)call
ラベルと呼び出し先は実際に ESP、EBP、およびその他のレジスタを操作する必要があるため、私にはあまり意味がありません。また、なぜ中間のラベルが必要なのか、もっと言えば、それなしで方法はありますか?