Skip to content

Commit 1f9dd8a

Browse files
authored
Merge pull request #538 from rustcoreutils/updates
cc, editor Updates
2 parents 3d8c6dc + 76e6106 commit 1f9dd8a

File tree

18 files changed

+1422
-655
lines changed

18 files changed

+1422
-655
lines changed

cc/main.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ use symbol::SymbolTable;
3838
use target::Os;
3939
use target::Target;
4040
use token::{
41-
preprocess_with_defines, show_token, token_type_name, PreprocessConfig, StreamTable, Tokenizer,
41+
preprocess_asm_file, preprocess_with_defines, show_token, token_type_name, AsmPreprocessConfig,
42+
PreprocessConfig, StreamTable, Tokenizer,
4243
};
4344

4445
// ============================================================================
@@ -724,24 +725,29 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
724725

725726
// .S files need preprocessing, .s files don't
726727
let asm_to_assemble = if asm_path.ends_with(".S") {
727-
// Preprocess with cpp
728+
// Preprocess with internal preprocessor (assembly mode)
728729
let temp_s = format!("/tmp/pcc_{}_{}.s", std::process::id(), stem);
729-
let mut cpp_cmd = Command::new("cpp");
730-
// Add include paths
731-
for inc in &args.include_paths {
732-
cpp_cmd.arg(format!("-I{}", inc));
733-
}
734-
// Add defines
735-
for def in &args.defines {
736-
cpp_cmd.arg(format!("-D{}", def));
737-
}
738-
if args.no_std_inc {
739-
cpp_cmd.arg("-nostdinc");
730+
let content = match std::fs::read(asm_path) {
731+
Ok(c) => c,
732+
Err(e) => {
733+
eprintln!("pcc: cannot read '{}': {}", asm_path, e);
734+
std::process::exit(1);
735+
}
736+
};
737+
let asm_config = AsmPreprocessConfig {
738+
defines: &args.defines,
739+
undefines: &args.undefines,
740+
include_paths: &args.include_paths,
741+
no_std_inc: args.no_std_inc,
742+
};
743+
let preprocessed = preprocess_asm_file(&content, &target, asm_path, &asm_config);
744+
// Check for preprocessor errors (e.g., #error directive, missing include)
745+
if diag::has_error() != 0 {
746+
eprintln!("pcc: preprocessing failed for {}", asm_path);
747+
std::process::exit(1);
740748
}
741-
cpp_cmd.args(["-o", &temp_s, asm_path]);
742-
let status = cpp_cmd.status()?;
743-
if !status.success() {
744-
eprintln!("pcc: preprocessor failed for {}", asm_path);
749+
if let Err(e) = std::fs::write(&temp_s, &preprocessed) {
750+
eprintln!("pcc: cannot write '{}': {}", temp_s, e);
745751
std::process::exit(1);
746752
}
747753
temp_s

cc/tests/codegen/misc.rs

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,17 @@ fn codegen_asm_file_support() {
399399
// invocation requires passing asm objects to C file's link step (future work).
400400

401401
// Assembly function that returns 42 (x86_64)
402+
// Note: macOS Mach-O uses underscore prefix and has no .type/.size directives
403+
#[cfg(target_os = "macos")]
404+
let asm_content = r#"
405+
.text
406+
.globl _get_value
407+
_get_value:
408+
movl $42, %eax
409+
ret
410+
"#;
411+
412+
#[cfg(not(target_os = "macos"))]
402413
let asm_content = r#"
403414
.text
404415
.globl get_value
@@ -410,6 +421,17 @@ get_value:
410421
"#;
411422

412423
// Assembly with preprocessor directives (.S) (x86_64)
424+
#[cfg(target_os = "macos")]
425+
let asm_s_content = r#"
426+
#define RETURN_VALUE 99
427+
.text
428+
.globl _get_value_s
429+
_get_value_s:
430+
movl $RETURN_VALUE, %eax
431+
ret
432+
"#;
433+
434+
#[cfg(not(target_os = "macos"))]
413435
let asm_s_content = r#"
414436
#define RETURN_VALUE 99
415437
.text
@@ -530,3 +552,128 @@ int main(void) {
530552
exit_code
531553
);
532554
}
555+
556+
/// Test that __ASSEMBLER__ is defined when preprocessing .S files
557+
#[cfg(target_arch = "x86_64")]
558+
#[test]
559+
fn codegen_asm_assembler_macro() {
560+
// Test that __ASSEMBLER__ is defined in .S files and that
561+
// #ifdef __ASSEMBLER__ conditional compilation works
562+
563+
// Assembly with __ASSEMBLER__ conditional
564+
#[cfg(target_os = "macos")]
565+
let asm_s_content = r#"
566+
#ifdef __ASSEMBLER__
567+
#define RETURN_VALUE 77
568+
#else
569+
#error "__ASSEMBLER__ should be defined"
570+
#endif
571+
.text
572+
.globl _get_asm_value
573+
_get_asm_value:
574+
movl $RETURN_VALUE, %eax
575+
ret
576+
"#;
577+
578+
#[cfg(not(target_os = "macos"))]
579+
let asm_s_content = r#"
580+
#ifdef __ASSEMBLER__
581+
#define RETURN_VALUE 77
582+
#else
583+
#error "__ASSEMBLER__ should be defined"
584+
#endif
585+
.text
586+
.globl get_asm_value
587+
.type get_asm_value, @function
588+
get_asm_value:
589+
movl $RETURN_VALUE, %eax
590+
ret
591+
.size get_asm_value, .-get_asm_value
592+
"#;
593+
594+
// C main that calls the asm function
595+
let c_content = r#"
596+
extern int get_asm_value(void);
597+
598+
int main(void) {
599+
if (get_asm_value() != 77) return 1;
600+
return 0;
601+
}
602+
"#;
603+
604+
let asm_s_file = create_asm_file("asm_assembler_test", asm_s_content, ".S");
605+
let c_file = create_c_file("asm_assembler_main", c_content);
606+
607+
let obj_asm = std::env::temp_dir().join(format!("pcc_asm_macro_{}.o", std::process::id()));
608+
let obj_c = std::env::temp_dir().join(format!("pcc_asm_macro_c_{}.o", std::process::id()));
609+
let exe_path = std::env::temp_dir().join(format!("pcc_asm_macro_test_{}", std::process::id()));
610+
611+
// Step 1: Compile .S to .o (with preprocessing, should have __ASSEMBLER__ defined)
612+
let output = run_test_base(
613+
"pcc",
614+
&vec![
615+
"-c".to_string(),
616+
"-o".to_string(),
617+
obj_asm.to_string_lossy().to_string(),
618+
asm_s_file.path().to_string_lossy().to_string(),
619+
],
620+
&[],
621+
);
622+
assert!(
623+
output.status.success(),
624+
"pcc -c .S with __ASSEMBLER__ failed: {}",
625+
String::from_utf8_lossy(&output.stderr)
626+
);
627+
628+
// Step 2: Compile C to .o
629+
let output = run_test_base(
630+
"pcc",
631+
&vec![
632+
"-c".to_string(),
633+
"-o".to_string(),
634+
obj_c.to_string_lossy().to_string(),
635+
c_file.path().to_string_lossy().to_string(),
636+
],
637+
&[],
638+
);
639+
assert!(
640+
output.status.success(),
641+
"pcc -c .c failed: {}",
642+
String::from_utf8_lossy(&output.stderr)
643+
);
644+
645+
// Step 3: Link
646+
let output = run_test_base(
647+
"pcc",
648+
&vec![
649+
"-o".to_string(),
650+
exe_path.to_string_lossy().to_string(),
651+
obj_c.to_string_lossy().to_string(),
652+
obj_asm.to_string_lossy().to_string(),
653+
],
654+
&[],
655+
);
656+
assert!(
657+
output.status.success(),
658+
"pcc link failed: {}",
659+
String::from_utf8_lossy(&output.stderr)
660+
);
661+
662+
// Run the executable
663+
let run_output = Command::new(&exe_path)
664+
.output()
665+
.expect("failed to run executable");
666+
667+
let exit_code = run_output.status.code().unwrap_or(-1);
668+
669+
// Cleanup
670+
let _ = std::fs::remove_file(&obj_asm);
671+
let _ = std::fs::remove_file(&obj_c);
672+
let _ = std::fs::remove_file(&exe_path);
673+
674+
assert_eq!(
675+
exit_code, 0,
676+
"__ASSEMBLER__ macro test failed with exit code {}",
677+
exit_code
678+
);
679+
}

0 commit comments

Comments
 (0)