將這更多地視爲僞代碼而不是任何東西。如果您覺得應該包含一些宏觀或其他元素,請告訴我。cedecl調用約定 - 編譯後的asm指令導致崩潰
我很喜歡裝配。我在大學時在一臺PIC處理器上編程,但從此沒有任何事。
這裏的問題(分段故障)是「編譯功能入口,設置堆棧幀」之後的第一條指令。或「推送%ebp」。下面是我發現了關於這兩個指令:
http://unixwiz.net/techtips/win32-callconv-asm.html
保存和更新%EBP:
現在,我們在新的功能,我們需要一個新的本地棧幀指以%ebp表示,所以這是通過保存當前的%ebp(屬於前一個函數的框架)並將其指向棧頂來完成的。
push ebp
mov ebp, esp // ebp « esp
一旦%ebp的已經被改變,它現在可以直接參考函數的參數爲8(%EBP),12(%EBP)。請注意,0(%ebp)是舊的基本指針,4(%ebp)是舊的指令指針。
這是代碼。這是來自我正在開發的項目的JIT編譯器。我比其他任何東西都更喜歡學習體驗。
IL_CORE_COMPILE(avs_x86_compiler_compile)
{
X86GlobalData *gd = X86_GLOBALDATA(ctx);
ILInstruction *insn;
avs_debug(print("X86: Compiling started..."));
/* Initialize X86 Assembler opcode context */
x86_context_init(&gd->ctx, 4096, 1024*1024);
/* Compile function entrance, setup stack frame*/
x86_emit1(&gd->ctx, pushl, ebp);
x86_emit2(&gd->ctx, movl, esp, ebp);
/* Setup floating point rounding mode to integer truncation */
x86_emit2(&gd->ctx, subl, imm(8), esp);
x86_emit1(&gd->ctx, fstcw, disp(0, esp));
x86_emit2(&gd->ctx, movl, disp(0, esp), eax);
x86_emit2(&gd->ctx, orl, imm(0xc00), eax);
x86_emit2(&gd->ctx, movl, eax, disp(4, esp));
x86_emit1(&gd->ctx, fldcw, disp(4, esp));
for (insn=avs_il_tree_base(tree); insn != NULL; insn = insn->next) {
avs_debug(print("X86: Compiling instruction: %p", insn));
compile_opcode(gd, obj, insn);
}
/* Restore floating point rounding mode */
x86_emit1(&gd->ctx, fldcw, disp(0, esp));
x86_emit2(&gd->ctx, addl, imm(8), esp);
/* Cleanup stack frame */
x86_emit0(&gd->ctx, emms);
x86_emit0(&gd->ctx, leave);
x86_emit0(&gd->ctx, ret);
/* Link machine */
obj->run = (AvsRunnableExecuteCall) gd->ctx.buf;
return 0;
}
當obj->運行被調用,這就是所謂的所有與obj作爲其唯一參數:
obj->run(obj);
如果有幫助,這裏是整個函數調用的指令。這基本上是一項分配操作:foo=3*0.2;
。 FOO指向一個浮在C.
0x8067990: push %ebp
0x8067991: mov %esp,%ebp
0x8067993: sub $0x8,%esp
0x8067999: fnstcw (%esp)
0x806799c: mov (%esp),%eax
0x806799f: or $0xc00,%eax
0x80679a4: mov %eax,0x4(%esp)
0x80679a8: fldcw 0x4(%esp)
0x80679ac: flds 0x806793c
0x80679b2: fsts 0x805f014
0x80679b8: fstps 0x8067954
0x80679be: fldcw (%esp)
0x80679c1: add $0x8,%esp
0x80679c7: emms
0x80679c9: leave
0x80679ca: ret
編輯:如我上面所說的,在本功能的第一條指令,%EBP是無效的。這也是導致分段錯誤的指令。那是因爲它是無效的,還是我在尋找別的東西?
編輯:劃痕。我繼續輸入edp而不是ebp。這裏是ebp和esp的值。
(gdb) print $esp
$1 = (void *) 0xbffff14c
(gdb) print $ebp
$3 = (void *) 0xbffff168
編輯:上面的這些值是錯誤的。我應該用「X」命令,如下圖所示:
(gdb) x/x $ebp
0xbffff168: 0xbffff188
(gdb) x/x $esp
0xbffff14c: 0x0804e481
下面是從別人對此郵件列表上的回覆。任何人都在意照亮他的意思嗎?如何檢查堆棧設置?
一個直接的問題,我看到的是, 堆棧指針未對齊。 這是32位代碼,英特爾 手冊指出堆棧應該是 ,它們在32位地址處對齊。也就是說, esp 中的最低有效位應該是0,4,8或c。我也注意到ebp和 esp的值相差很遠。通常, 它們包含相似的值 - 地址在堆棧中的某處。
我會看看如何在這個程序中設置堆棧 。
他回覆了對上述評論的更正。經過進一步的投入後,他無法看到任何問題。
另一編輯:有人回覆說,代碼頁可能沒有標記爲可執行文件。我怎樣才能確保它被標記爲這樣?
在另一個說明中,您是使用Intel還是AT&T彙編語法?您似乎在使用AT&T(基於'mov%esp,%ebp'行); unixwiz的例子使用英特爾。 – outis 2010-01-22 03:28:11
'$ esp'的價值是什麼? – outis 2010-01-22 03:29:22
@outis:是的,我在這裏使用AT&T。 – Scott 2010-01-22 03:29:51