[英]C++ | How can i delete files in a folder located in (C:\Program Files (x86))
[英]How do I link a C++ subroutine to an x86 assembly program?
我正在嘗試制作一個簡單的匯編程序,打印出“Hello!” 一次,等待一秒鍾,然后再打印出來。 由於睡眠功能在組裝時相對復雜,而且我不擅長它,所以我決定使用C ++來制作Sleep子程序。 這是C ++程序:
// Sleep.cpp
#include <thread>
#include <chrono>
void Sleep(int TimeMs) {
std::this_thread::sleep_for(std::chrono::milliseconds(TimeMs));
}
然后我使用“gcc -S Sleep.cpp”將這個睡眠函數編譯成匯編程序,然后使用“gcc -c Sleep.s”將其編譯成目標文件。
我試圖從匯編中調用這個C ++子例程。 我聽說你通過將它們推入堆棧來為C ++子程序提供參數,這是我到目前為止的匯編代碼:
global _main
extern _puts
extern Sleep
section .text
_main:
push rbp
mov rbp, rsp
sub rsp, 32
;Prompt user:
lea rdi, [rel prompt] ; First argument is address of message
call _puts ; puts(message)
push 1000 ; Wait 1 second (Sleep time is in milliseconds)
call Sleep
lea rdi, [rel prompt] ; Print hello again
call _puts
xor rax, rax ; Return 0
leave
ret
section .data
prompt:
db "Hello!", 0
這兩個文件都保存到桌面/程序。 我正在嘗試使用NASM和GCC編譯它,我的編譯器調用是:
nasm -f macho64 Program.asm && gcc Program.o Sleep.s -o Program && ./Program
但我得到錯誤:
"Sleep", referenced from:
_main in Program.o
(maybe you meant: __Z5Sleepi)
"std::__1::this_thread::sleep_for(std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000000000l> > const&)", referenced from:
void std::__1::this_thread::sleep_for<long long, std::__1::ratio<1l, 1000l> >(std::__1::chrono::duration<long long, std::__1::ratio<1l, 1000l> > const&) in Sleep-7749e0.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
將代碼更改為“extern __Z5Sleepi”並調用“__Z5Sleepi”而不是Sleep似乎無法解決問題。 (我得到了相同的錯誤信息,沒有“也許你的意思__Z5Sleepi”位。我也嘗試使用_Sleep而不是Sleep而沒有成功。)我做錯了什么? 如何正確使用和鏈接此C ++子例程與匯編程序? 到目前為止我使用的方法從頭開始做錯了嗎?
任何幫助都非常感激,瀏覽堆棧溢出,似乎有很多關於此的問題,但它們實際上都沒有進入鏈接過程。 (他們似乎在詢問是否將程序集與C ++相關聯,而不是將C ++與匯編相關聯。)我正在使用NASM和GCC進行編譯,而我的平台是Mac OSX。
正如傑斯特所指出的那樣,問題產生於兩件事。 一個是我需要更改Sleep.cpp程序以使用extern“C”,如下所示:
#include <thread>
#include <chrono>
extern "C" void Sleep(int TimeMS);
extern "C"
{
void Sleep(int TimeMs) {
std::this_thread::sleep_for(std::chrono::milliseconds(TimeMs));
}
}
這可以防止編譯器“命名修改”該函數。 這樣做會將Sleep()的已編譯函數名從“__Z5Sleepi”更改為“_Sleep”,並減輕了我的鏈接器錯誤。
然后我將編譯器調用更改為與g++
而不是gcc
鏈接,以鏈接C ++標准庫,用於函數,如std::__1::this_thread::sleep_for
,以及C標准庫。
nasm -f macho64 Program.asm && g++ Program.o Sleep.o -o Program && ./Program
在此之后,編譯器告訴我我需要將extern Sleep
更改為extern _Sleep
並且call _Sleep
而不是call Sleep
,因為OS X用前導_
裝飾C符號名稱。
在完成所有這些之后,程序正確鏈接但產生了分段錯誤。 Jester指出這是因為x86-64調用約定不會在棧上傳遞整數/指針函數參數。 您可以像調用_printf或_puts一樣使用寄存器,因為這些庫函數也遵循相同的標准調用約定。
在x86-64 System V調用約定(用於OS X,Linux和Windows以外的所有內容)中, rdi
是參數1 。
所以我把push 1000
改為mov rdi, 1000
完成所有這些更改后,程序將正確編譯並完全按照它應該執行的操作:打印Hello !,等待1秒鍾,然后再次打印。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.