[英]Calling a void function(int) with a void(*)(void) pointer and prepare stack yourself with arguments
我有一個void(*)(void)
函數指針,該指針實際上是一個void f(int)
。 關鍵是,我目前不知道它是什么樣的函數,所以我不能簡單地將其void(*)(int)
為void(*)(int)
。 我以為我可以簡單地使用函數的參數准備堆棧。
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main(int argc, char* argv[]) {
int* ptr = &argc - 8;
*ptr = -1;
printf("%p : %d\n", ptr, *ptr);
void (*f)(void) = (void(*)(void)) &func;
f();
return 0;
}
返回:
0x7ffd72ec204c : -1
0x7ffd72ec204c : 0
我希望它返回-1
兩次。 但是,似乎gcc在調用函數時添加了一些代碼來清除堆棧,這就是為什么func()
改為顯示0
原因。
是否有某種編譯器標志可用於禁用該標志?
我正在使用gcc (Debian 4.9.2-10) 4.9.2
,但是如果我可以在任何編譯器中使用它,那就足夠了! 我的一致是Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt20-1+deb8u3 (2016-01-17) x86_64 GNU/Linux
。
我已閱讀過有關MUST_PASS_IN_STACK
-可以幫上忙嗎? 如果可以,該如何使用?
我知道這不是最佳做法。 這只是一個理論練習。
您可以插入特定於平台的匯編語言代碼以完成所需的操作。 請注意,它不可移植。
讓我們看一下程序的稍微簡化版本的兩個版本:
版本1(簡潔代碼):
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main() {
void (*f)(int) = &func;
f(-2);
return 0;
}
第2版(駭客程式碼):
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main() {
void (*f)(void) = (void (*)(void))&func;
return 0;
}
您可以使用gcc -S
生成兩個版本的匯編代碼。
我的環境中版本1的匯編代碼:
.file "soc.c"
.section .rdata,"dr"
.LC0:
.ascii "%p : %d\12\0"
.text
.globl func
.def func; .scl 2; .type 32; .endef
.seh_proc func
func:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movl 16(%rbp), %eax
movl %eax, %r8d
leaq 16(%rbp), %rdx
leaq .LC0(%rip), %rcx
call printf
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
leaq func(%rip), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
movl $-2, %ecx
call *%rax
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 4.9.3"
.def printf; .scl 2; .type 32; .endef
我的環境中版本2的匯編代碼:
.file "soc.c"
.section .rdata,"dr"
.LC0:
.ascii "%p : %d\12\0"
.text
.globl func
.def func; .scl 2; .type 32; .endef
.seh_proc func
func:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movl 16(%rbp), %eax
movl %eax, %r8d
leaq 16(%rbp), %rdx
leaq .LC0(%rip), %rcx
call printf
nop
addq $32, %rsp
popq %rbp
ret
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
leaq func(%rip), %rax
movq %rax, -8(%rbp)
movq -8(%rbp), %rax
call *%rax
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (GNU) 4.9.3"
.def printf; .scl 2; .type 32; .endef
兩個版本的匯編代碼之間的唯一區別是第44行。
movl $-2, %ecx
如果將相同的匯編代碼注入到程序的第二個版本中,則:
#include <stdio.h>
void func(int x) {
printf("%p : %d\n", &x, x);
}
int main() {
void (*f)(void) = (void (*)(void))&func;
__asm__("movl $-2, %ecx");
f();
return 0;
}
編譯器生成預期的匯編代碼。 當我運行上述程序時,我得到:
0x22cae0 : -2
與您在該程序的第一個版本中看到的輸出相同。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.