Skip to content

Commit

Permalink
Merge pull request #79 from byeongkeunahn/run-macos
Browse files Browse the repository at this point in the history
Support macOS (AArch64)
  • Loading branch information
kiwiyou authored Feb 14, 2024
2 parents 7de7ebe + 2fb7889 commit 39c81a8
Show file tree
Hide file tree
Showing 27 changed files with 382 additions and 37 deletions.
6 changes: 5 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
rustflags = ["-Z", "share-generics=no", "-Z", "export-executable-symbols", "-C", "target-feature=+avx,+avx2,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+fma,+f16c,+aes", "-C", "relocation-model=pie", "-C", "target-cpu=haswell"]

[target.aarch64-apple-darwin]
rustflags = ["-Z", "share-generics=no", "-Z", "export-executable-symbols", "-C", "relocation-model=pie"]
rustflags = ["-Z", "share-generics=no", "-C", "relocation-model=pie"]

[target.x86_64-pc-windows-gnu]
rustflags = ["-Z", "share-generics=no", "-Z", "export-executable-symbols", "-C", "lto=thin", "-C", "target-feature=+avx,+avx2,+sse,+sse2,+sse3,+ssse3,+sse4.1,+sse4.2,+fma,+f16c,+aes", "-C", "relocation-model=pie", "-C", "target-cpu=haswell"]
linker = "x86_64-w64-mingw32-gcc"

[target.wasm32-unknown-unknown]
rustflags = ["-Z", "share-generics=no", "-C", "link-args=-z stack-size=67108864"]
2 changes: 1 addition & 1 deletion .cargo/x86_64-unknown-linux-gnu-short.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"cpu": "x86-64",
"crt-objects-fallback": "false",
"crt-static-respected": true,
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"dynamic-linking": true,
"eh-frame-header": false,
"env": "gnu",
Expand Down
18 changes: 16 additions & 2 deletions .github/workflows/build-linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
matrix:
target:
- x86_64-unknown-linux-gnu
- x86_64-pc-windows-gnu
- i686-unknown-linux-gnu
- wasm32-unknown-unknown
env:
Expand All @@ -38,15 +39,20 @@ jobs:
- name: Install System packages
run: |
sudo apt update
sudo apt install gcc-multilib nasm
sudo apt install gcc-multilib nasm mingw-w64 gcc-mingw-w64
rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
python -m pip install pefile
- name: Clippy
run: cargo clippy
env:
RUSTFLAGS: "-D warnings -A clippy::missing_safety_doc"
- name: Test
if: ${{ matrix.target != 'wasm32-unknown-unknown' }}
if: ${{ matrix.target != 'wasm32-unknown-unknown' && matrix.target != 'x86_64-pc-windows-gnu' }}
run: cargo test --lib -- --test-threads 1
- name: Check cargo build --release
if: ${{ matrix.target != 'wasm32-unknown-unknown' && matrix.target != 'x86_64-pc-windows-gnu' }}
run: |
python ./scripts/ci.py ${{ runner.temp }} _ Cargo 0 ./tests/ci.json
- name: Check C (x86_64)
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
run: |
Expand All @@ -55,6 +61,10 @@ jobs:
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
run: |
python ./scripts/ci.py ${{ runner.temp }} ./.github/workflows/release-short.sh C 64 ./tests/ci.json
- name: Check C (x86_64) - MinGW64
if: ${{ matrix.target == 'x86_64-pc-windows-gnu' }}
run: |
python ./scripts/ci.py ${{ runner.temp }} ./release-64bit-mingw.sh C 64 ./tests/ci.json
- name: Check C (x86)
if: ${{ matrix.target == 'i686-unknown-linux-gnu' }}
run: |
Expand All @@ -67,6 +77,10 @@ jobs:
if: ${{ matrix.target == 'x86_64-unknown-linux-gnu' }}
run: |
python ./scripts/ci.py ${{ runner.temp }} ./.github/workflows/release-rs-short.sh Rust 64 ./tests/ci.json
- name: Check Rust (x86_64) - MinGW64
if: ${{ matrix.target == 'x86_64-pc-windows-gnu' }}
run: |
python ./scripts/ci.py ${{ runner.temp }} ./release-rs-mingw.sh Rust 64 ./tests/ci.json
- name: Check wasm32
if: ${{ matrix.target == 'wasm32-unknown-unknown' }}
run: |
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ jobs:
- name: Test
if: ${{ matrix.target != 'wasm32-unknown-unknown' }}
run: cargo test --lib -- --test-threads 1
- name: Check cargo build --release
if: ${{ matrix.target != 'wasm32-unknown-unknown' }}
run: |
python3 ./scripts/ci.py ${{ runner.temp }} _ Cargo 0 ./tests/ci.json
- name: Check wasm32
if: ${{ matrix.target == 'wasm32-unknown-unknown' }}
run: |
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ jobs:
- name: Test
if: ${{ matrix.target != 'wasm32-unknown-unknown' }}
run: cargo test --lib -- --test-threads 1
- name: Check cargo build --release
if: ${{ matrix.target != 'wasm32-unknown-unknown' }}
run: |
python .\scripts\ci.py ${{ runner.temp }} _ Cargo 0 .\tests\ci.json
- name: Check C (x86_64)
if: ${{ matrix.target == 'x86_64-pc-windows-msvc' }}
run: |
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,8 @@ basm.bin
Cargo.lock
/[Tt]mp
*.obj
*.pyc
*.pyc
.DS_Store
._.DS_Store
**/.DS_Store
**/._.DS_Store
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ Linux (WSL 포함) 환경에서 빌드하는 방법입니다.

* VS Code의 `build-release-wasm32-submit` Task를 실행하면 릴리즈 모드 빌드 후 제출 가능한 JavaScript (wasm32) 코드가 VS Code 편집기에서 열립니다.

macOS (AArch64) 환경에서 빌드하는 방법입니다.

* `release-64bit-mingw.sh`를 실행하면 64비트 환경(백준 온라인 저지, 코드포스 등)에 제출 가능한 C 코드가 출력됩니다.

* `release-rs-mingw.sh`를 실행하면 64비트 리눅스 환경(백준 온라인 저지 등)에 제출 가능한 Rust 코드가 출력됩니다. 생성된 코드를 Windows에서 컴파일하려면 crate type을 `cdylib`에서 `bin`으로 변경해야 합니다.

* `release-wasm32.sh`를 실행하면 제출 가능한 JavaScript (wasm32) 코드가 출력됩니다.

* `release-html.sh`를 실행하면 입력에 대한 출력을 계산할 수 있는 인터랙티브 HTML 페이지가 출력됩니다.

* VS Code의 `build-release-wasm32-submit` Task를 실행하면 릴리즈 모드 빌드 후 제출 가능한 JavaScript (wasm32) 코드가 VS Code 편집기에서 열립니다.

## 디버깅

> Windows 11 64비트, Windows Subsystems for Linux 2 (WSL2)에서 테스트되었습니다. 다른 환경에서 작동에 문제가 있을 시 이슈를 남겨주세요.
Expand All @@ -160,12 +172,14 @@ Linux (WSL 포함) 환경에서 빌드하는 방법입니다.

- Linux에서 Binutils를 요구합니다.

- Windows에서 Python 3 라이브러리 `pefile`을 요구합니다.
- Windows 및 macOS에서 Python 3 라이브러리 `pefile`을 요구합니다.

- Windows에서 빌드하기 위해서 Microsoft C/C++ 컴파일러가 필요합니다. 가장 간단한 방법은 최신 버전의 Visual Studio를 설치하는 것입니다. 아래 링크를 참고하시면 도움이 됩니다.
- https://learn.microsoft.com/ko-kr/windows/dev-environment/rust/setup
- https://rust-lang.github.io/rustup/installation/windows-msvc.html

- macOS에서 빌드하기 위해서 MinGW가 필요합니다. 홈브루(패키지 매니저의 일종)를 설치하신 다음 `brew install mingw-w64`를 통해 설치해주세요.

- `std`를 사용할 수 없습니다. 단, `cargo test` 시에는 `std`를 사용할 수 있습니다.

- `libc`를 사용할 수 없습니다.
Expand All @@ -176,15 +190,15 @@ Linux (WSL 포함) 환경에서 빌드하는 방법입니다.

- 메모리 할당을 C runtime 없이 구현하기 위해 [dlmalloc](https://github.com/alexcrichton/dlmalloc-rs)이 적용되어 있습니다. 대부분의 경우 잘 작동하지만, 만약 실행시간이나 메모리 사용량이 2-3배 이상 과도하게 증가하는 등의 문제를 겪으신다면 꼭(!) 이슈를 남겨주세요.

- Windows도 아니고 Linux도 아닌 환경에서는 테스트되지 않았습니다. 이러한 환경에서는 현재 구현상 C runtime의 malloc을 사용하므로 메모리 할당이 정렬되지 않기 때문에 문제가 발생할 수 있습니다. 문제를 겪으시는 경우 이슈를 남겨주세요.
- Windows, Linux, macOS에서만 테스트되었습니다. 그 외의 환경에서 문제를 겪으시는 경우 이슈를 남겨주세요.

- Linux 환경에서 빌드하여 출력된 코드를 Windows 환경에서 컴파일하여 실행하는 경우 정상 작동을 보장할 수 없습니다. 이는 Linux 컴파일러가 Windows에서 사용하는 `__chkstk` 메커니즘을 지원하지 않기 때문입니다. Windows 환경에서 컴파일하여 실행해야 하는 경우 가급적 Windows 환경에서 빌드해 주세요. 이것이 어렵다면 하나의 함수 내에서 스택을 한 번에 4KB를 초과하여 이용하지 않도록 주의해주세요. 한편, Windows 환경에서 빌드하여 출력된 코드는 `__chkstk` 메커니즘을 포함하고 있으나 Windows가 아닌 환경에서 실행되는 경우 이를 비활성화하도록 구현되어 있기 때문에 Windows 및 Linux에서 모두 정상 작동이 가능합니다.

- Rust 코드 형태로 빌드한 경우 Windows 환경에서 컴파일하여 실행하기 위해서는 코드 상단에 crate type을 `cdylib`로 지정하는 부분을 제거해 주세요. (코드포스 등)

- 코드 구조 수정으로 인해 Assembly 코드로 변환하는 기능은 지원되지 않습니다.

- 현재 ARM은 32비트/64비트 둘 다 지원되지 않습니다. 지원이 필요하시면 이슈를 남겨주세요.
- 현재 ARM은 macOS 64비트 (`aarch64-apple-darwin`) 한정으로 `cargo run`이 지원됩니다. 단, ARM 32비트는 지원하지 않습니다. 또한, macOS에서 ARM 타겟 제출용 빌드는 불가하며, 홈브루를 통해 `MinGW64`를 설치 후(`brew install mingw-w64`) "mingw"로 끝나는 셸 스크립트를 통해 제출용 x86_64 빌드가 가능합니다. 사용상 문제가 있으신 경우 이슈를 남겨주세요.

- 기타 빌드 및 실행 또는 디버깅 등에 문제가 있는 경우 이슈를 남겨주세요.

Expand Down
6 changes: 6 additions & 0 deletions basm-std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }

[target.x86_64-pc-windows-msvc.dependencies]
compiler_builtins = { version = "0.1.103", features = ["mem"] }
[target.x86_64-pc-windows-gnu.dependencies]
compiler_builtins = { version = "0.1.103", features = ["mem"] }
[target.x86_64-unknown-linux-gnu.dependencies]
compiler_builtins = { version = "0.1.103", features = ["mem"] }
[target.i686-unknown-linux-gnu.dependencies]
compiler_builtins = { version = "0.1.103", features = ["mem"] }
[target.aarch64-apple-darwin.dependencies]
compiler_builtins = { version = "0.1.103", features = ["mem"] }
[target.wasm32-unknown-unknown.dependencies]
compiler_builtins = { version = "0.1.103", features = ["mem"] }

Expand All @@ -30,3 +34,5 @@ compiler_builtins = { version = "0.1.103", features = ["mem"] }
codegen = []
# Favors short routines for code golf.
short = []
# Configures the crate for submission.
submit = []
49 changes: 46 additions & 3 deletions basm-std/src/platform/codegen.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[cfg(not(any(target_arch = "wasm32", target_arch = "aarch64")))]
#[cfg(not(target_arch = "wasm32"))]
use core::arch::asm;

use crate::platform;
Expand Down Expand Up @@ -44,6 +44,9 @@ use crate::platform::loader;
#[cfg(not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64", target_arch = "wasm32")))]
compile_error!("The target architecture is not supported.");

#[cfg(all(target_arch = "aarch64", feature = "submit"))]
compile_error!("AArch64 (aarch64-apple-darwin) is only supported for local execution, not submission; use x86-64 to submit.");

#[cfg(all(target_arch = "x86_64", not(target_os = "windows")))]
#[no_mangle]
#[naked]
Expand Down Expand Up @@ -93,6 +96,19 @@ unsafe extern "sysv64" fn get_kernel32() -> usize {
LoadLibraryA(b"KERNEL32\0".as_ptr())
}

#[cfg(all(target_os = "windows", target_env = "gnu"))]
mod chkstk_gnu {
extern "C" {
pub fn ___chkstk_ms();
pub fn ___chkstk();
}
}
#[cfg(all(target_os = "windows", not(target_env = "gnu")))]
mod chkstk_gnu {
pub extern "C" fn ___chkstk_ms() {}
pub extern "C" fn ___chkstk() {}
}

#[cfg(all(target_arch = "x86_64", target_os = "windows"))]
#[no_mangle]
#[naked]
Expand Down Expand Up @@ -134,6 +150,8 @@ pub unsafe extern "win64" fn _basm_start() -> ! {
// https://learn.microsoft.com/en-us/cpp/build/prolog-and-epilog
// 0: c3 ret
"mov BYTE PTR [rip + {2}], 0xc3",
"mov BYTE PTR [rip + {5}], 0xc3",
"mov BYTE PTR [rip + {6}], 0xc3",
// END Linux patch
"3:",
"mov rcx, rbx",
Expand All @@ -145,6 +163,8 @@ pub unsafe extern "win64" fn _basm_start() -> ! {
sym __chkstk,
sym get_kernel32,
sym GetProcAddress,
sym chkstk_gnu::___chkstk_ms,
sym chkstk_gnu::___chkstk,
options(noreturn)
);
}
Expand Down Expand Up @@ -232,6 +252,24 @@ pub extern "C" fn _basm_start() {
_start_rust(&mut pd as *mut platform::services::PlatformData as usize);
}

#[cfg(target_arch = "aarch64")]
#[no_mangle]
#[naked]
#[repr(align(8))]
pub unsafe extern "C" fn _basm_start() -> ! {
asm!(
"sub sp, sp, #96",
"mov x0, #4", // 4 = ENV_ID_MACOS
"str x0, [sp, #(8 * 0)]",
"mov x0, #2", // 2 = ENV_FLAGS_NATIVE
"str x0, [sp, #(8 * 1)]",
"mov x0, sp",
"bl {0}",
sym _start_rust,
options(noreturn)
)
}

/* We prevent inlining solution::main, since if the user allocates
* a large amount of stack memory there, it will be zero-initialized (or probed)
* *before* we increase the stack limits if it is inlined into _start_rust.
Expand Down Expand Up @@ -294,9 +332,14 @@ pub unsafe fn print_panicinfo_and_exit(_pi: &core::panic::PanicInfo) -> ! {
}
ExitProcess(101)
}
#[cfg(target_os = "linux")] {
#[cfg(target_os = "linux")]
{
crate::platform::os::linux::syscall::exit_group(101)
}
#[cfg(not(any(all(windows, target_arch = "x86_64"), target_os = "linux")))]
#[cfg(target_os = "macos")]
{
crate::platform::os::macos::syscall::exit_group(101)
}
#[cfg(not(any(all(windows, target_arch = "x86_64"), target_os = "linux", target_os = "macos")))]
core::hint::unreachable_unchecked()
}
61 changes: 61 additions & 0 deletions basm-std/src/platform/malloc/dlmalloc_macos.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#![allow(clippy::not_unsafe_ptr_arg_deref)]

use super::dlmalloc_interface::DlmallocAllocator;
use super::super::os::macos::syscall;


pub struct System {
_priv: (),
}

impl System {
pub const fn new() -> System {
System { _priv: () }
}
}

unsafe impl DlmallocAllocator for System {
fn alloc(&self, size: usize) -> (*mut u8, usize, u32) {
let addr = unsafe {
syscall::mmap(
core::ptr::null_mut(),
size,
syscall::PROT_WRITE | syscall::PROT_READ,
syscall::MAP_ANON | syscall::MAP_PRIVATE,
-1,
0,
)
};
if core::ptr::eq(addr, syscall::MAP_FAILED) {
(core::ptr::null_mut(), 0, 0)
} else {
(addr, size, 0)
}
}

#[allow(unused)]
fn remap(&self, ptr: *mut u8, oldsize: usize, newsize: usize, can_move: bool) -> *mut u8 {
core::ptr::null_mut()
}

#[allow(unused)]
fn free_part(&self, ptr: *mut u8, oldsize: usize, newsize: usize) -> bool {
false
}

fn free(&self, ptr: *mut u8, size: usize) -> bool {
unsafe { syscall::munmap(ptr as *mut _, size).is_null() }
}

fn can_release_part(&self, _flags: u32) -> bool {
false
}

fn allocates_zeros(&self) -> bool {
true
}

fn page_size(&self) -> usize {
4096
}
}
6 changes: 4 additions & 2 deletions basm-std/src/platform/malloc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
pub mod dlmalloc_interface;
pub mod dlmalloc;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(any(target_arch = "wasm32", target_arch = "aarch64")))]
pub mod dlmalloc_windows;
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(any(target_arch = "wasm32", target_arch = "aarch64")))]
pub mod dlmalloc_linux;
#[cfg(target_arch = "aarch64")]
pub mod dlmalloc_macos;
#[cfg(target_arch = "wasm32")]
pub mod dlmalloc_wasm32;
14 changes: 10 additions & 4 deletions basm-std/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,21 @@ pub fn init(platform_data_by_loader: usize) {
let pd = services::platform_data();
unsafe {
match pd.env_id {
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(any(target_arch = "wasm32", target_arch = "aarch64")))]
#[cfg(not(feature = "short"))]
services::ENV_ID_WINDOWS => {
/* use OS APIs directly */
os::windows::init();
},
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(any(target_arch = "wasm32", target_arch = "aarch64")))]
services::ENV_ID_LINUX => {
/* use syscalls directly */
os::linux::init();
},
#[cfg(target_arch = "aarch64")]
services::ENV_ID_MACOS => {
os::macos::init();
},
#[cfg(target_arch = "wasm32")]
services::ENV_ID_WASM => {
/* wasm32-specific */
Expand All @@ -48,10 +52,12 @@ pub fn init(platform_data_by_loader: usize) {
#[cfg(not(test))]
pub fn try_exit() {
let pd = services::platform_data();
if pd.env_id == services::ENV_ID_LINUX &&
if (pd.env_id == services::ENV_ID_LINUX || pd.env_id == services::ENV_ID_MACOS) &&
(pd.env_flags & services::ENV_FLAGS_NO_EXIT) == 0 {
#[cfg(not(target_arch = "wasm32"))]
#[cfg(not(any(target_arch = "wasm32", target_arch = "aarch64")))]
unsafe { os::linux::syscall::exit_group(services::get_exit_status() as usize); }
#[cfg(target_arch = "aarch64")]
unsafe { os::macos::syscall::exit_group(services::get_exit_status() as usize); }
}
}
#[cfg(not(test))]
Expand Down
Loading

0 comments on commit 39c81a8

Please sign in to comment.