在每一行之后似乎都有一个.CFI指令,而且这些ex..cfi_startproc,.cfi_endproc等等的变化很大. 这里更多.
.file "temp.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.globl func
.type func, @function
func:
.LFB1:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movl %edi, -4(%rbp)
movl %esi, %eax
movb %al, -8(%rbp)
leave
ret
.cfi_endproc
.LFE1:
.size func, .-func
.ident "GCC: (Ubuntu 4.4.1-4ubuntu9) …Run Code Online (Sandbox Code Playgroud) 我编写空程序来惹恼stackoverflow程序员的地狱,不是.我正在探索gnu工具链.
现在以下对我来说可能太深了,但是为了继续执行空程序传奇,我已经开始检查C编译器的输出,GNU作为消耗的东西.
gcc version 4.4.0 (TDM-1 mingw32)
Run Code Online (Sandbox Code Playgroud)
test.c的:
int main()
{
return 0;
}
Run Code Online (Sandbox Code Playgroud)
gcc -S test.c
.file "test.c"
.def ___main; .scl 2; .type 32; .endef
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
call ___main
movl $0, %eax
leave
ret
Run Code Online (Sandbox Code Playgroud)
你能解释一下这里发生的事吗?这是我努力理解它.我使用了as手册和我的最小x86 ASM知识:
.file "test.c" 是逻辑文件名的指令..def:根据文档"开始定义符号名称的调试信息".什么是符号(函数名称/变量?)以及什么样的调试信息?.scl:docs说"存储类可以标记符号是静态的还是外部的".这是我从C中知道的静态和外部吗?什么是'2'?.type:存储参数"作为符号表条目的类型属性",我不知道..endef: 没问题..text:现在这是有问题的,它似乎是一个叫做section的东西,我已经读过它的代码所在,但是文档并没有告诉我太多. …在我使用以下转出的汇编代码中objdump:
lea 0x0(%esi,%eiz,1),%esi
Run Code Online (Sandbox Code Playgroud)
什么是注册%eiz?前面的代码是什么意思?
我想解释一下GCC生成的汇编中.cfi_def_cfa_offset指令使用的值.我隐约知道.cfi指令涉及调用帧和堆栈展开,但我想更详细地解释为什么,例如,在编译以下C程序时GCC输出的汇编中使用值16和8的原因在我的64位Ubuntu机器上.
C程序:
#include <stdio.h>
int main(int argc, char** argv)
{
printf("%d", 0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我在源文件test.c上调用了GCC,如下所示:gcc -S -O3 test.c.我知道-O3可以实现非标准优化,但为了简洁起见,我想限制生成的程序集的大小.
生成的程序集:
.file "test.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "%d"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB22:
.cfi_startproc
subq $8, %rsp
.cfi_def_cfa_offset 16
xorl %edx, %edx
movl $.LC0, %esi
movl $1, %edi
xorl %eax, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE22:
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits …Run Code Online (Sandbox Code Playgroud) 在学习"汇编语言"(在使用GNU作为汇编程序的x86架构上的linux中)时,其中一个时刻就是使用系统调用的可能性.这些系统调用非常方便,有时甚至是必需的,因为您的程序在用户空间中运行.
然而,系统调用在性能方面相当昂贵,因为它们需要中断(当然还有系统调用),这意味着必须从用户空间中的当前活动程序到内核空间中运行的系统进行上下文切换.
我想说的是:我目前正在实现一个编译器(用于大学项目),我想要添加的一个额外功能是支持多线程代码以提高编译程序的性能.因为一些多线程代码将由编译器本身自动生成,所以这几乎可以保证其中也会有很少的多线程代码.为了获得性能,我必须确保使用线程可以实现这一点.
但我担心的是,为了使用线程,我必须进行系统调用和必要的中断.因此,微小的(自动生成的)线程将受到进行这些系统调用所花费的时间的极大影响,这甚至可能导致性能损失......
因此,我的问题是双重的(在其下面有一个额外的奖励问题):
我的猜测是没有系统调用就不可能有多线程汇编程序代码.即使是这种情况,您是否有建议(甚至更好:一些实际代码)尽可能高效地实现线程?
我并没有试图提示英特尔与AT&T之争(无论如何,现在他们都支持英特尔语法)或者问哪一个本身"更好",我只是想知道选择其中一个的实际差异. .
基本上,当我几年前拿起一些基本的x86组件时,除了我正在阅读的那本书之外,我没有理由使用NASM - 这让我坚定但不由自主地进入了NASM阵营.从那时起,我使用汇编的原因很少,所以我没有机会尝试GAS.
请记住,它们都支持英特尔语法(我个人更喜欢),理论上至少应该生成相同的二进制文件(我知道它们可能不会,但意思不应该改变),有什么理由支持非此即彼?
是命令行选项吗?宏?非助记符关键字?或者是其他东西?
谢谢 :)
如何在AMD64架构的Linux汇编程序中使用RIP相对寻址?我正在寻找一个使用AMD64 RIP相对地址模式的简单示例(Hello world程序).
例如,以下64位汇编程序将与普通(绝对寻址)一起使用:
.text
.global _start
_start:
mov $0xd, %rdx
mov $msg, %rsi
pushq $0x1
pop %rax
mov %rax, %rdi
syscall
xor %rdi, %rdi
pushq $0x3c
pop %rax
syscall
.data
msg:
.ascii "Hello world!\n"
Run Code Online (Sandbox Code Playgroud)
我猜测使用RIP相对寻址的相同程序将是这样的:
.text
.global _start
_start:
mov $0xd, %rdx
mov msg(%rip), %rsi
pushq $0x1
pop %rax
mov %rax, %rdi
syscall
xor %rdi, %rdi
pushq $0x3c
pop %rax
syscall
msg:
.ascii "Hello world!\n"
Run Code Online (Sandbox Code Playgroud)
编译时,正常版本运行正常:
as -o hello.o hello.s && ld -s -o hello hello.o && ./hello
Run Code Online (Sandbox Code Playgroud)
但我无法使RIP版本正常工作. …
我正在尝试在程序集中使用函数,从C项目调用.这个函数应该调用一个libc函数printf(),但我一直遇到分段错误.
在.c文件中,我有函数的声明让我们说
int do_shit_in_asm()
Run Code Online (Sandbox Code Playgroud)
在我的.asm文件中
.extern printf
.section .data
printtext:
.ascii "test"
.section .text
.global do_shit_in_asm
.type do_shit_in_asm, @function
do_shit_in_asm:
pushl %ebp
movl %esp, %ebp
push printtext
call printf
movl %ebp, %esp
pop %ebp
ret
Run Code Online (Sandbox Code Playgroud)
任何指针评论将不胜感激.
as func.asm -o func.o
gcc prog.c func.o -o prog
Run Code Online (Sandbox Code Playgroud) 0x0000000000400553 <main+59>: mov -0x4(%rbp),%eax
0x0000000000400556 <main+62>: cltq
0x0000000000400558 <main+64>: shl $0x3,%rax
0x000000000040055c <main+68>: mov %rax,%rdx
Run Code Online (Sandbox Code Playgroud)
事实上,我的程序很简单:
5 int main(int argc, char *argv[]) {
6 int i = 0;
7 while(environ[i]) {
8 printf("%s\n", environ[i++]);
9 }
10 return 0;
Run Code Online (Sandbox Code Playgroud)
但是程序集输出很长:
Dump of assembler code for function main:
0x0000000000400518 <main+0>: push %rbp
0x0000000000400519 <main+1>: mov %rsp,%rbp
0x000000000040051c <main+4>: sub $0x20,%rsp
0x0000000000400520 <main+8>: mov %edi,-0x14(%rbp)
0x0000000000400523 <main+11>: mov %rsi,-0x20(%rbp)
0x0000000000400527 <main+15>: movl $0x0,-0x4(%rbp)
0x000000000040052e <main+22>: jmp 0x400553 <main+59>
0x0000000000400530 <main+24>: mov -0x4(%rbp),%eax …Run Code Online (Sandbox Code Playgroud) 这是一个奇怪的要求,但我觉得它有可能.我想要的是将一些编译指示或指令插入到我的代码区域(用C编写),以便GCC的寄存器分配器不会使用它们.
我知道我可以做这样的事情,这可能会为这个变量留下这个寄存器
register int var1 asm ("EBX") = 1984;
register int var2 asm ("r9") = 101;
Run Code Online (Sandbox Code Playgroud)
问题是我直接插入新指令(用于硬件模拟器),而GCC和GAS还没有识别出这些指令.我的新指令可以使用现有的通用寄存器,我想确保我保留了一些(即r12-> r15).
现在,我在一个模拟环境中工作,我想快速做我的实验.将来我会添加GAS并将内在函数添加到GCC中,但是现在我正在寻找快速修复.
谢谢!