分享
 
 
 

Linux下的汇编器

王朝system·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

Linux 下两个最主要的汇编器是 Nasm(free, Netwide Assembler)和 GAS(free, Gnu A

ssembler),

后一个和 GCC 结合在一起. 在这篇文章里我将集中在 Nasm 上, 把 GAS 放在后面,

因为它使用 AT&T 的语法, 需要一个长的介绍.

Nasm 调用时应该带上 ELF 格式选项("nasm -f elf hello.asm"); 产生的目标文件用

GCC 来链接("gcc hello.o"), 产生最终的 ELF 二进制代码. 下面的这个脚本可用来

编译 ASM 的模块; 我尽量把它写得简单, 所以所有它做的就是接受传给它的第一个

文件名, 用 Nasm 编译, 用 GCC 来链接.

#!/bin/sh

# assemble.sh =========================================================

outfile=${1%%.*}

tempfile=asmtemp.o

nasm -o $tempfile -f elf $1

gcc $tempfile -o $outfile

rm $tempfile -f

#EOF ==================================================================

基本知识:

----------

当然最好的就是在了解系统细节之前从一个例子开始. 这里是一个最基本的

"hello-word" 形式的程序:

; asmhello.asm ========================================================

global main

extern printf

section .data

msg db "Helloooooo, nurse!",0Dh,0Ah,0

section .text

main:

push dword msg

call printf

pop eax

ret

; EOF =================================================================

纲要: "global main" 必须声明为全局的(global) -- 并且既然我们用 GCC 来链接,

进入点必须以 "main" 来命名 -- 从而装入系统. "extern printf" 只是一个声明,

为以后在程序中调用; 注意这是必须的; 参数的大小不需要声明. 我已经把这个

例子用标准的 .data, .text 分节, 但这不是严格必须的 -- 可能只需要一个 .text

段, 就像在 DOS 下一样.

在代码的主体部分, 你必须把参数压栈来传递给调用. 在 Nasm 里, 你必须声明

所有不明确数据的大小; 因此就有 "dword" 这个限定词. 注意和其他汇编器一样,

Nasm 假设所有的内存/标号的引用都指的是内存地址或者标号, 而不是它的内容.

因而, 指明字符串 'msg' 的地址, 你应该使用 'push dword msg', 指明字符串 'msg'

的内容, 应该用 'push dword [msg]' (这只能包含 'msg' 的前四个字节). 因为 prin

tf

需要一个指向字符串的指针, 我们应该指明 'msg' 的地址.

调用 printf 非常的直接. 注意每一次调用后你必须把栈清除(见下); 所以 PUSH 了一

dword 后, 我从栈里把一个 dword POP 进一个无用的寄存器. Linux 程序只简单的用一

个 RET 来返回系统, 由于每个进程都是 shell(或者是 PID)的产物, 所以程序结束后把

控制权还给它.

注意到在 Linux 下, 你是在 "API" 或中断服务的场所里使用系统带来的标准共享库.

所有

的外部引用由 GCC 管理, 它给 asm 程序员节省了大部分的工作. 一旦你习惯了基本的

巧, Linux 下的汇编编程实际上要比 DOS 简单的多.

C 调用的语法

--------------------

Linux 使用 C 的调用模式 -- 意味着参数以相反的顺序进栈(最后一个最先), 调用者必

须清

除栈. 你可以从栈里把值 pop 出来:

push dword szText

call puts

pop ecx

或者直接修改 ESP:

push dword szText

call puts

add esp, 4

调用的返回值在 eax 或 edx:eax 如果值大于 32 位的话. EBP, ESI, EDI, EBX 由调用

保存和恢复. 你必须保存你要使用的寄存器, 像下面这样:

; loop.asm =================================================================

global main

extern printf

section .text

msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0

main:

mov ecx, 0Ah

push dword msg

looper:

call printf

loop looper

pop eax

ret

; EOF ======================================================================

粗一看, 非常简单: 因为你在 10 个 printf() 调用用的是同一个字符串, 你不需要清

除栈. 但当你编译以后, 循环不会停止. 为什么? 因为 printf() 里什么地方用了 ECX

但没有保存. 使你的循环正确的工作, 你必须在调用之前保存 ECX 的值, 调用之后

恢复它, 像这样:

; loop.asm ================================================================

global main

extern printf

section .text

msg db "HoodooVoodoo WeedooVoodoo",0Dh,0Ah,0

main:

mov ecx, 0Ah

looper:

push ecx ;save Count

push dword msg

call printf

pop eax ;cleanup stack

pop ecx ;restore Count

loop looper

ret

; EOF ======================================================================

I/O 端口编程

--------------------

但直接访问硬件会怎么样呢? 在 Linux 下你需要一个核心模式的驱动程序来做这些

工作... 这意味着你的程序必须分成两个部分, 一个核心模式提供硬件直接操作的功

能, 其他的用户模式提供接口. 一个好消息就是你仍然可以在用户模式的程序中使用

IN/OUT 来访问端口.

要访问端口你的程序必须取得系统的同意; 要做这个, 你必须调用 ioperm(). 这个函

数只能被有 root 权限的用户使用, 所以你必须用 setuid() 使程序到 root 或者直接

运行在 root 下. ioperm() 的语法是这样:

ioperm( long StartingPort#, long #Ports, BOOL ToggleOn-Off)

'StartingPort#' 指明要访问的第一个端口值(0 是端口 0h, 40h 是端口 40h, 等等),

'#Ports'

指明要访问多少个端口(也就是说, 'StartingPort# = 30h', '#Port = 10', 可以访问

端口

30h - 39h), 'ToggleOn-Off' 如果是 TRUE(1) 就能够访问, 是 FALSE(0) 就不能访问

.

一旦调用了 ioperm(), 要求的端口就和平常一样访问. 程序可以调用 ioperm() 任意多

次,

而不需要在后来调用 ioperm()(但下面的例子这样做了), 因为系统会处理这些.

; io.asm ===================================================================

=

BITS 32

GLOBAL szHello

GLOBAL main

EXTERN printf

EXTERN ioperm

SECTION .data

szText1 db 'Enabling I/O Port Access',0Ah,0Dh,0

szText2 db 'Disabling I/O Port Acess',0Ah,0Dh,0

szDone db 'Done!',0Ah,0Dh,0

szError db 'Error in ioperm() call!',0Ah,0Dh,0

szEqual db 'Output/Input bytes are equal.',0Ah,0Dh,0

szChange db 'Output/Input bytes changed.',0Ah,0Dh,0

SECTION .text

main:

push dword szText1

call printf

pop ecx

enable_IO:

push word 1 ; enable mode

push dword 04h ; four ports

push dword 40h ; start with port 40

call ioperm ; Must be SUID "root" for this call!

add ESP, 10 ; cleanup stack (method 1)

cmp eax, 0 ; check ioperm() results

jne Error

;---------------------------------------Port Programming Part--------------

SetControl:

mov al, 96 ; R/W low byte of Counter2, mode 3

out 43h, al ; port 43h = control register

WritePort:

mov bl, 0EEh ; value to send to speaker timer

mov al, bl

out 42h, al ; port 42h = speaker timer

ReadPort:

in al, 42h

cmp al, bl ; byte should have changed--this IS a timer

jne ByteChanged

BytesEqual:

push dword szEqual

call printf

pop ecx

jmp disable_IO

ByteChanged:

push dword szChange

call printf

pop ecx

;---------------------------------------End Port Programming Part----------

disable_IO:

push dword szText2

call printf

pop ecx

push word 0 ; disable mode

push dword 04h ; four ports

push dword 40h ; start with port 40h

call ioperm

pop ecx ;cleanup stack (method 2)

pop ecx

pop cx

cmp eax, 0 ; check ioperm() results

jne Error

jmp Exit

Error:

push dword szError

call printf

pop ecx

Exit:

ret

; EOF ===

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有