@@ -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