【C編程】彙編語言文件

C編程時,我們可能需要做一些彙編語言編程,以增加granularity。另外,在Xcode debug時,會跳入彙編語言程序。

彙編語言的程序結構如下。[1]


# PURPOSE:
#          Simple program that exits and returns a 
#          status code back to the Linux kernel

# INPUT:   none

# OUTPUT:  returns a status code.This can be viewed by typing 'echo $'?

#          after running the program

# VARIABLES:
#          %eax holds the system call number
#          %ebx holds the return status

#
#.section _data
#.section _text
.globl _start
_start:
    movl $1, %eax         # this is the linux kernel command
                          # number (system call) for exiting
                          # a program

    movl $0, %ebx         # this is the status number we will
                          # return to the operating system.
                          # Change this around and it will
                          # return different things to
                          # echo $?

    int $0x80             # this wakes up the kernel to run
                          # the exit command

這是C exit(0)對應的彙編語言,eax存儲system call number,ebx存儲返回值。可用echo $?查看返回值。

以.開頭的叫偽指令或者彙編指示器,偽指令是為了指導彙編器,彙編器會處理這些指令,而不會直接被翻譯成機器代碼。比如,.section將程序分割成多個section。

#是彙編語言程序的註釋。

以上代碼存為exit.s。先經assembler編譯為.o文件,再經linker生成可執行程序。

我的機器是MacOS 10.14.5。本例我的實際操作是:

as exit.s -o exit.o

gcc exit.o -o exit

echo $?

使用彙編語言編譯器as編譯為.o文件。再用gcc將.o編譯為可執行程序。使用gcc而不是ld,是因為我嘗試了,不成功,有的程序可以ld成功。


每個機器不同的處理器,彙編語言不同。如何適應?

我想從C語言編譯的彙編文件學習。

比如hello.c程序:


#include <stdio.h>

int main() {
  printf("您好,世界。");
  return 0;
} 

gcc -save-temps hello.c

gcc編譯依次經過1)預處理器(preprocessor)生成的.i文件;2)C編譯器,生成彙編語言程序.s文件;3)彙編編譯器,生成目標代碼.o文件,這是代碼;4)Linker,在操作系統註冊,生成可執行程序。-save-temps參數可讓我們看到過程文檔。[2]

打開hello.s。

    .section    __TEXT,__text,regular,pure_instructions
    .build_version macos, 10, 14    sdk_version 10, 15
    .globl    _main                   ## -- Begin function main
    .p2align    4, 0x90
_main:                                  ## @main
    .cfi_startproc
## %bb.0:
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register %rbp
    subq    $16, %rsp
    movl    $0, -4(%rbp)
    leaq    L_.str(%rip), %rdi
    movb    $0, %al
    callq    _printf
    xorl    %ecx, %ecx
    movl    %eax, -8(%rbp)          ## 4-byte Spill
    movl    %ecx, %eax
    addq    $16, %rsp
    popq    %rbp
    retq
    .cfi_endproc
                                        ## -- End function
    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ## @.str
    .asciz    "\346\202\250\345\245\275\357\274\214\344\270\226\347\225\214\343\200\202"


.subsections_via_symbols

這裏exit部分看起來用到了eax,ecx。中文UTF8編碼用ASCII碼的八進制顯示,\346=3*64+4*8+6=230=\xe6, \202=\x82, \250=\xa8,每個中文字三個字節,在Terminal printf "\346\202\250"顯示『您』,printf "\xe6\x82\xa8"亦同。


另一個Hello World程序的代碼是這樣的:[3]


.global start
.intel_syntax noprefix

start:
    # Write "Hello World"
    mov rax, 0x2000004                # system call 4 (write code)
    mov rdi, 1
    lea rsi, hello_world[rip]
    mov rdx, 12                       # Set register rdx to 12
    syscall                           # envoke syscall

    # Exit program
    mov rax, 0x2000001                # system call 1 (exit code)
    mov rdi, 99                       # set the exit code to 99
    syscall

hello_world:                          # Definition of hello_world
    .asciz "Hello World\n"

為什麼是rax,rdi?這些寄存器好像有包含和被包含、整體和部分的關係。但我也還不清楚。這機器編譯的.s文件難得多吧?其實我看不懂,我只是計劃這樣學習彙編語言。

這裏是彙編語言整體的命令查詢。[4]



參考:


  1. Jason Note,如何在linux下編譯彙編程序,內功心法是彙編程序的結構,https://jasonblog.github.io/note/assembly/ru_he_zai_linux_xia_bian_yi_hui_bian_cheng_xu_ff0c.html ↩︎

  2. Tiffany的世界,[GCC]GCC常用命令和参数,2025-07-08,https://zhuanlan.zhihu.com/p/1925840990817740428 ↩︎

  3. Getting Started with Assembly on x86-64 MacOS: Hello World, https://zerodayarcade.com/tutorials/hello-world-assembly-macos ↩︎

  4. 彙編,https://www.newton.com.tw/wiki/彙編 ↩︎

posted @ 2025-12-12 18:17  Dersu  阅读(1)  评论(0)    收藏  举报