2010-09-10 26 views
5

Mô tả này hợp lệ đối với Linux 32 bit: Khi chương trình Linux bắt đầu, tất cả các con trỏ tới đối số dòng lệnh được lưu trữ trên ngăn xếp. Số lượng đối số được lưu trữ tại 0 (% ebp), tên của chương trình được lưu trữ ở mức 4 (% ebp) và các đối số được lưu trữ từ 8 (% ebp).Linux 64 tham số dòng lệnh trong Assembly

Tôi cần thông tin tương tự cho 64 bit.

Edit: Tôi đã làm việc mẫu mã trong đó cho thấy làm thế nào để sử dụng argc, argv [0] và argv [1]: http://cubbi.com/fibonacci/asm.html

 
.globl _start 
_start: 
    popq %rcx  # this is argc, must be 2 for one argument 
    cmpq $2,%rcx 
    jne  usage_exit 
    addq $8,%rsp  # skip argv[0] 
    popq %rsi  # get argv[1] 
    call ... 
... 
} 

Dường như thông số trên stack. Vì mã này không rõ ràng, tôi hỏi câu hỏi này. Tôi đoán rằng tôi có thể giữ rsp trong rbp, và sau đó truy cập các thông số này bằng cách sử dụng 0 (% rbp), 8 (% rbp), 16 (% rbp) vv. Điều này có đúng không?

Trả lời

9

Có vẻ như phần 3.4 Quá trình khởi tạo và đặc biệt là hình 3.9, trong đã đề cập System V AMD64 ABI mô tả chính xác những gì bạn muốn biết.

+2

Chỉ liên kết câu trả lời là mong manh. Trang đó không hiệu quả với tôi. * www.x86-64.org không gửi bất kỳ dữ liệu nào. ERR_EMPTY_RESPONSE * – doug65536

1

Tôi tin rằng những gì bạn cần làm là kiểm tra x86-64 ABI. Cụ thể, tôi nghĩ bạn cần xem phần 3.2.3 Tham số thông qua.

+2

Điều này mô tả quy ước gọi điện bên trong chương trình. Quy trình dòng lệnh tham số có thể có quy tắc riêng của họ. Tôi cần thông tin cụ thể này cho Linux 64. –

8

Mặc dù câu trả lời được chấp nhận là quá đủ, tôi muốn đưa ra câu trả lời rõ ràng, vì có một số câu trả lời khác có thể gây nhầm lẫn.

Quan trọng nhất (để biết thêm thông tin xem các ví dụ dưới đây): trong x86-64 các đối số dòng lệnh được truyền qua chồng:

(%rsp) -> number of arguments 
8(%rsp) -> address of the name of the executable 
16(%rsp) -> address of the first command line argument (if exists) 
... so on ... 

Đó là khác biệt so với các tham số chức năng đi qua trong x86-64, trong đó sử dụng %rdi, %rsi v.v.

Một điều nữa: không nên suy ra hành vi từ kỹ thuật đảo ngược của C main-chức năng. Thời gian chạy C cung cấp điểm nhập _start, kết thúc các đối số dòng lệnh và gọi main làm chức năng chung. Để xem nó, hãy xem xét ví dụ sau.

Không C runtime/GCC với -nostdlib

Hãy kiểm tra chương trình x86-64 lắp ráp đơn giản này, mà không phải làm gì nhưng trả 42:

.section .text 
.globl _start 
_start: 
    movq $60, %rax #60 -> exit 
    movq $42, %rdi #return 42 
    syscall #run kernel 

Chúng tôi xây dựng nó với:

as --64 exit64.s -o exit64.o 
ld -m elf_x86_64 exit64.o -o exit64 

hoặc với

gcc -nostdlib exit64.s -o exit64 

chạy trong gdb với

./exit64 first second third 

và dừng lại ở breakpoint tại _start. Hãy kiểm tra sổ đăng ký:

(gdb) info registers 
... 
rsi   0x0 0 
rdi   0x0 0 
... 

Không có gì ở đó. Điều gì về ngăn xếp?

(gdb) x/5g $sp 
0x7fffffffde40: 4 140737488347650 
0x7fffffffde50: 140737488347711 140737488347717 
0x7fffffffde60: 140737488347724 

Vì vậy, phần tử đầu tiên trên ngăn xếp là 4 - mong đợi argc. 4 giá trị tiếp theo trông rất giống con trỏ. Hãy xem con trỏ thứ hai:

(gdb) print (char[5])*(140737488347711) 
$1 = "first" 

Như dự kiến, đây là đối số dòng lệnh đầu tiên.

Vì vậy, có bằng chứng thực nghiệm, rằng các đối số dòng lệnh được chuyển qua ngăn xếp trong x86-64. Tuy nhiên chỉ bằng cách đọc các ABI (như câu trả lời được chấp nhận đề nghị) chúng tôi có thể chắc chắn, rằng đây thực sự là trường hợp.

Với C runtime

Chúng ta phải thay đổi chương trình một chút, đổi tên _start vào main, bởi vì điểm vào _start được cung cấp bởi các runtime C.

.section .text 
.globl main 
main: 
    movq $60, %rax #60 -> exit 
    movq $42, %rdi #return 42 
    syscall #run kernel 

Chúng tôi xây dựng nó với (C runtime được sử dụng mỗi mặc định):

gcc exit64gcc.s -o exit64gcc 

chạy trong gdb với

./exit64gcc first second third 

và dừng lại ở breakpoint tại main. Có gì ở ngăn xếp?

(gdb) x/5g $sp 
0x7fffffffdd58: 0x00007ffff7a36f45 0x0000000000000000 
0x7fffffffdd68: 0x00007fffffffde38 0x0000000400000000 
0x7fffffffdd78: 0x00000000004004ed 

Nó trông không quen thuộc. Và đăng ký?

(gdb) info registers 
... 
rsi   0x7fffffffde38 140737488346680 
rdi   0x4 4 
... 

Chúng tôi có thể thấy rằng rdi chứa giá trị argc. Nhưng nếu bây giờ chúng ta kiểm tra con trỏ trong rsi những điều kỳ lạ xảy ra:

(gdb) print (char[5])*($rsi) 
$1 = "\211\307???" 

Nhưng chờ đợi, đối số thứ hai của main hàm trong C không phải là char *, nhưng char ** thêm:

(gdb) print (unsigned long long [4])*($rsi) 
$8 = {140737488347644, 140737488347708, 140737488347714, 140737488347721} 
(gdb) print (char[5])*(140737488347708) 
$9 = "first" 

Và bây giờ chúng tôi tìm thấy các đối số của chúng tôi, được thông qua qua sổ đăng ký vì nó sẽ là một hàm bình thường trong x86-64.

Kết luận: Như chúng ta có thể thấy, sự khác biệt liên quan đến việc truyền các đối số dòng lệnh giữa mã sử dụng thời gian chạy C và mã không có.

+1

Bạn có thể xây dựng một chương trình xác định '_start' [bằng cách sử dụng' gcc -nostdlib'] (http://stackoverflow.com/questions/36861903/assembling-32-bit-binaries-on-a-64-bit- system-gnu-toolchain/36901649 # 36901649). Nếu bạn chỉ định nghĩa 'main', không phải' _start', bạn phải sử dụng gcc, nhưng việc định nghĩa '_start' không ngăn bạn sử dụng gcc. –

+0

Nhìn vào sổ đăng ký/bộ nhớ là một cách hay để tìm hiểu xem có thể * hoạt động như thế nào, tức là tìm thứ gì đó để tìm kiếm để tìm tài liệu chính thức.Bạn không nên chỉ giả định rằng bất cứ điều gì bạn tìm thấy được đảm bảo là có, mặc dù. Bạn không muốn phụ thuộc vào một cái gì đó thực sự chỉ là một bản sao chép còn sót lại, và có thể không có trong một phiên bản tương lai. Kết luận của bạn là chính xác, nhưng sẽ tốt hơn nếu bạn tiếp tục tham khảo cách SysV ABI đảm bảo rằng những giá trị đó sẽ có ở đó. –

+0

Bạn cũng không đề cập đến mã CRT glibc cung cấp '_start' và gọi' main' của bạn. Không có sự khác biệt kỳ diệu giữa việc xác định 'main' hoặc' _start'; không khó để hiểu mã khởi động của trình khởi chạy nào để thu thập trạng thái khởi động quá trình và gọi 'main' với hàm args đó. –

Các vấn đề liên quan