考虑 x64 Intel 程序集中的以下变量引用,其中变量a在.data节中声明:
mov eax, dword ptr [rip + _a]
Run Code Online (Sandbox Code Playgroud)
我很难理解这个变量引用是如何工作的。既然a是对应于变量运行时地址的符号(带重定位),如何[rip + _a]解引用正确的内存位置a?事实上,rip保存当前指令的地址,它是一个大的正整数,所以加法会导致错误的地址a?
相反,如果我使用 x86 语法(非常直观):
mov eax, dword ptr [_a]
Run Code Online (Sandbox Code Playgroud)
,我收到以下错误:64 位模式不支持 32 位绝对寻址。
有什么解释吗?
1 int a = 5;
2
3 int main() {
4 int b = a;
5 return b;
6 }
Run Code Online (Sandbox Code Playgroud)
编译gcc -S -masm=intel abs_ref.c -o abs_ref::
1 .section __TEXT,__text,regular,pure_instructions
2 .build_version macos, 10, 14
3 …Run Code Online (Sandbox Code Playgroud) 作为一个练习来更准确地学习c程序如何工作以及程序能够使用libc必须存在的最低内容级别,我自己尝试使用gas和ld主要在x86程序集中进行编程.
作为一个有趣的小挑战,我已成功组装并链接了几个链接到不同自制动态库的程序,但是我无法从头开始编写程序以使用libc函数调用而无需直接使用gcc.
我了解单个c库函数的调用约定,并通过使用objdump和readelf彻底检查了gcc编译的程序,但是在气体汇编文件中包含哪些信息以及要调用的参数方面没有任何进展在ld中成功链接到libc.有人对此有任何见解吗?
我在x86机器上运行Linux.
我最近开始使用arm core进行汇编编程.我的第一个小演示,只有.text部分,没有任何问题.
作为一个逻辑扩展,我想将汇编代码构造成通常的部分:.text,.data,.bss.
所以我写了以下简单的程序:
.globl _start
.section .text
_start:
b main
b .
b .
b .
b .
b .
b .
b .
main:
ldr r0, x
nop
.section .data
x: .word 0xf0f0f0f0
.end
Run Code Online (Sandbox Code Playgroud)
但
/opt/arm/bin/arm-as -ggdb -mcpu=arm7tdmi demo.s -o demo.o
Run Code Online (Sandbox Code Playgroud)
退出并出错
prog.s: Assembler messages:
prog.s:17: Error: internal_relocation (type: OFFSET_IMM) not fixed up
make: *** [prog.o] Error 1
Run Code Online (Sandbox Code Playgroud)
我不知道为什么汇编程序抱怨重定位,因为我认为这是链接器的任务.我可以想象我必须告诉汇编程序我的.data部分不是在汇编阶段的最终内存位置,但我找不到任何相关的东西.
虽然我找到了一种方法来通过替换来正确组装代码
.section .data
Run Code Online (Sandbox Code Playgroud)
通过
.org .
Run Code Online (Sandbox Code Playgroud)
这不是一个令人满意的解决方案.特别是考虑到气体文件突出了这一部分的意义.
也许你的专家可以帮助我获得一些智慧
有谁知道如何摆脱以下汇编警告?
代码是x86,32位:
int test (int x)
{
int y;
// do a bit-rotate by 8 on the lower word. leave upper word intact.
asm ("rorw $8, %0\n\t": "=q"(y) :"0"(x));
return y;
}
Run Code Online (Sandbox Code Playgroud)
如果我编译它,我得到以下(非常有效)警告:
Warning: using `%ax' instead of `%eax' due to `w' suffix
Run Code Online (Sandbox Code Playgroud)
我正在寻找的是告诉编译器/汇编器我想要访问%0的低16位子寄存器的方法.访问字节子寄存器(在本例中为AL和AH)也很好.
我已经选择了"q"修饰符,因此编译器被迫使用EAX,EBX,ECX或EDX.我已经确保编译器必须选择一个具有子寄存器的寄存器.
我知道我可以强制asm-code使用特定的寄存器(及其子寄存器),但我想将寄存器分配作业留给编译器.
g ++编译器具有零成本异常处理功能.据我所知,try什么都不做,但是当抛出异常时,会执行异常处理程序的子例程.像这样:
void foo() {
try {
bar(); // throws.
} catch (Type exc) {
baz();
}
}
Run Code Online (Sandbox Code Playgroud)
伪代码(c-stylish)看起来像这样:
void foo() {
bar();
return;
catch1_Type:
baz();
}
Run Code Online (Sandbox Code Playgroud)
bar()抛出.例程例程执行以下操作:
啊,返回地址是函数foo()!并且返回地址在第一个try-catch块中,我们抛出类型Type,因此异常处理程序例程位于地址foo + catch1_Type.所以清理堆栈让我们最终到达那里!
现在我的问题是:有没有办法在C中实现它?(可以是C99或更新,虽然我对gcc支持的C语言感兴趣).我知道我可以使用例如libunwind进行堆栈检查和遍历,虽然我不知道如何获取catch1_Type标签的地址.这可能是不可能的.
异常处理程序可能是一个不同的函数,同样可以,但是如何foo在另一个函数中获取stackframe的局部变量的地址?这似乎也是不可能的.
所以...有什么办法吗?我不想用这个进入汇编程序,但如果其他一切都失败也是可以接受的(尽管局部变量 - 伙计,如果使用不同的优化级别,你永远不会知道它们在哪里).
并且要明确 - 这个问题的目的是避免使用 setjmp/longjmp方法.
编辑:我发现了一个非常酷的想法,但完全不起作用:
gcc中的嵌套函数.他们能做什么?
下行阻止我做任何零成本的事情:
我设法生成一个与QEMU 2.0.0 Ubuntu 14.04一起使用的最小引导扇区:
.code16
.global _start
_start:
cli
mov $msg, %si
mov $0x0e, %ah
loop:
lodsb
or %al, %al
jz halt
int $0x10
jmp loop
halt:
hlt
msg:
.asciz "hello world"
.org 510
.word 0xaa55
Run Code Online (Sandbox Code Playgroud)
编译:
as -o main.o main.S
ld --oformat binary -o main.img -Ttext 0x7C00 main.o
Run Code Online (Sandbox Code Playgroud)
这个例子可以在这个回购中找到:https://github.com/cirosantilli/x86-bare-metal-examples/tree/2b79ac21df801fbf4619d009411be6b9cd10e6e0/no-ld-script
一旦:
qemu -hda main.img
Run Code Online (Sandbox Code Playgroud)
它hello world按预期在模拟器屏幕上显示.
但是,如果我尝试刻录到USB:
sudo dd if=main.img of=/dev/sdb
Run Code Online (Sandbox Code Playgroud)
然后将USB插入ThinkPad T400或T430,点击F12,然后选择我观察到的USB:
我也用Ubuntu 14.04映像测试了相同的USB,它启动正常,因此USB工作正常.
我应该如何更改此示例,以便它将在硬件上启动并显示hello world消息?
Ubuntu图像和我创建的图像有什么区别?
这记录在哪里?
我已将sudo dmidecodeT400 …
我有以下C程序:
int main()
{
int c[10] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2};
return c[0];
}
Run Code Online (Sandbox Code Playgroud)
当使用带有gcc的-S指令编译时,我得到以下程序集:
.file "array.c"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
movl $0, -48(%rbp)
movl $0, -44(%rbp)
movl $0, -40(%rbp)
movl $0, -36(%rbp)
movl $0, -32(%rbp)
movl $0, -28(%rbp)
movl $0, -24(%rbp)
movl $0, -20(%rbp)
movl $1, -16(%rbp)
movl $2, -12(%rbp)
movl -48(%rbp), %eax
leave
.cfi_def_cfa 7, …Run Code Online (Sandbox Code Playgroud) 这两个工具都将汇编指令直接转换为机器代码,但是有可能确定哪一个生成最快,最干净的代码?
我正在研究GCC生成的汇编代码.但我不明白:
movl $0x2d, 0x4(%esp)
Run Code Online (Sandbox Code Playgroud)
在第二个操作数中,0x4代表什么?偏移地址?注册EAX有什么用?
我正在Android设备上编写针对ARM Cortex-A的代码(使用GNU汇编器和编译器),我正在尝试在Assembly和C之间进行接口.特别是,我有兴趣调用用C语言编写的函数.我尝试了很多东西,包括.extern指令,用asm和__asm__等声明C函数,但是没有一个工作,所以我正在寻找一个这样做的最小例子.对这样的例子的引用同样值得欢迎.
gnu-assembler ×10
assembly ×9
c ×4
x86 ×3
arm ×2
gcc ×2
bare-metal ×1
binutils ×1
cortex-a8 ×1
elf ×1
intel-syntax ×1
ld ×1
nasm ×1
optimization ×1
qemu ×1
x86-64 ×1